Rails中Turbo Stream响应异常为HTML的问题修复咨询
问题描述
我在profile/follow_button页面设置了如下turbo_frame_tag:
<%= turbo_frame_tag "#{dom_id(@user)} follow_user" do %> <% if following?(user) %> <%= link_to "Unfollow", profile_unfollow_path(id: user.id), method: :delete, class: "" %> <% else %> <%= link_to "Follow", profile_follow_path(id: user.id), method: :post, class: "" %> <% end %> <% end %>
为通过Hotwire实现点击加载关注/取消关注动作,我在控制器编写了如下代码:
def follow Relationship.create_or_find_by(follower_id: current_user.id, followee_id: @user.id) # redirect_back(fallback_location: root_path) respond_to do |format| format.turbo_stream do render turbo_stream: update_action_follow end end end def unfollow current_user.followed_user.where(follower_id: current_user.id, followee_id: @user.id).destroy_all # redirect_back(fallback_location: root_path) respond_to do |format| format.turbo_stream do render turbo_stream: update_action_follow end end end private def update_action_follow private_target = "#{dom_id_for_follower(@user)} follow_user" turbo_stream.replace(private_target, partial: 'profile/follow_button', locals: { user: @user }) end def update_count_follower private_target = "#{@user.id}-follower-count" turbo_stream.update(private_target, partial: 'profile/follower_count', locals: { user: @user }) end
预期响应格式应为TURBO_STREAM,但日志显示实际为HTML格式,进而出现报错,请问该如何解决?
解决方案
1. 让请求正确携带Turbo Stream标识
Hotwire Turbo需要请求携带text/vnd.turbo-stream.html的Accept头,才能触发控制器的format.turbo_stream分支。需要修改link_to,显式指定请求格式为turbo_stream,并确保Turbo处理该请求:
<%= turbo_frame_tag "#{dom_id(@user)} follow_user" do %> <% if following?(user) %> <%= link_to "Unfollow", profile_unfollow_path(id: user.id, format: :turbo_stream), method: :delete, class: "", data: { turbo: true } %> <% else %> <%= link_to "Follow", profile_follow_path(id: user.id, format: :turbo_stream), method: :post, class: "", data: { turbo: true } %> <% end %> <% end %>
2. 修正DOM ID匹配问题
控制器中update_action_follow方法里的目标ID,必须和视图中turbo_frame_tag的ID完全一致。当前代码使用dom_id_for_follower(@user),如果这个方法的逻辑和dom_id(@user)不同,就会导致无法找到目标元素。直接替换为视图中一致的写法:
def update_action_follow private_target = "#{dom_id(@user)} follow_user" turbo_stream.replace(private_target, partial: 'profile/follow_button', locals: { user: @user }) end
3. 确保控制器正确赋值并处理响应
在follow和unfollow方法中,必须确保@user被正确赋值,否则视图局部渲染会出错。同时添加HTML格式的 fallback,避免请求异常:
def follow @user = User.find(params[:id]) Relationship.create_or_find_by(follower_id: current_user.id, followee_id: @user.id) respond_to do |format| format.turbo_stream { render turbo_stream: update_action_follow } format.html { redirect_back fallback_location: root_path } end end def unfollow @user = User.find(params[:id]) current_user.followed_user.where(followee_id: @user.id).destroy_all respond_to do |format| format.turbo_stream { render turbo_stream: update_action_follow } format.html { redirect_back fallback_location: root_path } end end
4. 检查Turbo的引入状态
确认应用已正确加载Turbo:
- 检查
application.js中是否包含import "@hotwired/turbo-rails" - 确保布局文件里添加了
<%= turbo_include_tags %>(Rails 7+)或其他正确加载Turbo JS的方式
内容的提问来源于stack exchange,提问作者quocanhcute
相关产品推荐
相关产品推荐

