Rails的respond_to重定向不起作用。

3
在我的Rails应用程序中,create控制器中的respond_to块在成功保存时没有重定向...我相信这是一个简单的解决方案,但我对Rails缺乏经验,这是我第一次遇到这个问题。
表单被设置为:remote => true,控制器如下...
def create
    @store = current_user.stores.new(store_params)

    respond_to do |format|
        if @store.save
            format.html { redirect_to root_path }
        else
            format.html { flash[:alert] = "Save failed! #{@store.errors.full_messages.join(";")}" 
            render "new" }
            format.js {}
        end
    end
end

而且,当我谈到这个话题时,条件语句中else部分的代码也不会运行,除了format.js {},它会运行我的create.js.erb文件中的代码(目前是一个警报)。
我正在使用Rails 4.2.5。有人能帮我理解为什么重定向和警报不起作用吗?谢谢!
编辑以显示解决方案 基于Rich的答案,这是我想出的解决方案:
控制器:
def create
    @store = current_user.stores.new(store_params)

    flash.now[:alert] = "Save failed! #{@store.errors.full_messages.join(";")}" unless @store.save

    respond_to do |format|
        format.js
    end

    if @store.save
        flash[:notice] = "New store created"
    end
end

create.js.erb

<% if flash.now[:alert] %>
    $("#alert_holder").empty();
    $("#alert_holder").append("<%= j flash.now[:alert] %>");
<% else %>
    window.location.href = "<%= root_url %>";
<% end %>

请注意,我需要在重定向 URL 周围添加引号。
在表单成功提交后,页面将重定向到根目录。如果失败,则会闪现错误消息,但表单不会刷新 - 用户输入的任何答案都将保留。
2个回答

6

remote: true 是一个ajax请求。

Ajax是JavaScript,因此会调用format.js方法:

def create
    @store = current_user.stores.new store_params

    respond_to do |format|
        if @store.save
            format.js
            format.html { redirect_to root_path }
        else
            format.js
            format.html { flash[:alert] = "Save failed! #{@store.errors.full_messages.join(";")}" 
            render "new" }
        end
    end
end
< p > format.js 方法将调用 /app/views/[:controller]/[:action].js.erb 文件,其中将触发其中包含的任何 JS。< /p> < p > 如果您不希望使用 js 格式处理响应,则必须摆脱 respond_to,并只返回您想要返回的内容(redirect_to 将不起作用)。< /p>

Ajax

在这方面,您需要了解几个规定:

  • Ajax 不能自己“重定向”
  • Ajax 在 Rails 控制器中将被视为 JS
  • 您必须“黑客” flash 才能通过 JS 让它工作

如果您没有使用 Ajax 的经验,简单的解释是它是一个“伪请求”;它发送一个 HTTP 请求而不必重新加载浏览器。

Ajax 的模式很简单:Ajax 请求 > 服务器 > Ajax 响应

除非您使用 javascript 解析响应,否则无法通过 Ajax 进行“重定向”。正如 Ajax 首字母缩写(异步 JavaScript 和 XML)所示,响应应该是 XML(即无功能)。

--

为了回答您的问题,您需要使用flash.now来处理“flash”消息,并使用您的.js.erb文件处理响应。
def create
    @store = current_user.stores.new store_params
    flash.now[:alert] = "Save failed! #{@store.errors.full_messages.join(";")}" unless @store.save

    respond_to do |format|
        format.js
        format.html
    end
end

这将允许您调用...
#app/views/stores/create.js.erb
<% if flash.now[:alert] %> alert("<%=j flash.now[:alert] %>"); <% end %>
window.location.href = <%= root_url %>;

{{链接1:Ref}}


您的新代码可以稍作改进:

def create
    @store = current_user.stores.new store_params

    if @store.save
        flash[:notice] = "New store created"
    else
        flash.now[:alert] = "Save failed! #{@store.errors.full_messages.join(";")}"
    end

    respond_to do |format|
        format.js
    end
end

如果你想让你的代码更加DRY,你需要看一下responders gem:
#app/controllers/stores_controller.rb
class StoresController < ApplicationController
   respond_to :js, only: :create

   def create
      @store = ...
      respond_with @store if @store.save
   end
end

1
这真的很棒,我自己想不出来。感谢为Rails新手提供指导。 - skwidbreth
我已经编辑了我的问题,展示了基于您的指导得出的答案。虽然我需要微调一些细节,但现在它可以完美地工作了。 - skwidbreth

2
如果您的表单中有“remote: true”,则控制器检测到的格式将是“format.js”,这在成功的“@store.save”部分中不存在。
两个选项:
1. 默认使用普通表单提交(通过删除“remote: true”)。 2. 添加“format.js”,并加载另一个js.erb文件,就像else条款中那样,然后通过一些JavaScript在那里处理错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接