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

创建.js.erb

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

请注意,我需要在重定向 url 周围添加引号。

表单成功后,页面重定向到根目录。失败时,错误消息会闪烁,但表单不会刷新 - 用户输入的任何答案都会保留。

4

2 回答 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

format.js方法将调用该/app/views/[:controller]/[:action].js.erb文件,该文件将触发您在其中的任何 JS。

如果您不想让js格式处理响应,您将不得不取消respond_to并只拥有您想要返回的内容(redirect_to不会工作)。


阿贾克斯

您需要了解以下几个规定:

  • Ajax 不能“重定向”(单独)
  • Ajax 将被视为JS在 Rails 控制器中
  • 您必须“破解”闪光灯才能使其正常工作JS

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

Ajax 的模式很简单:Ajax request > server > Ajax response

除非您使用 javascript 解析响应,否则您不能通过 Ajax“重定向”。正如 Ajax 首字母缩写词(Asynchronous Javascript And XML)所暗示的,响应应该是 XML(IE 没有功能)。

--

要回答您的问题,您需要使用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 %>;

参考


您的新代码可以改进一点:

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提升您的代码,您将需要查看respondersgem:

#app/controllers/stores_controller.rb
class StoresController < ApplicationController
   respond_to :js, only: :create

   def create
      @store = ...
      respond_with @store if @store.save
   end
end
于 2016-01-29T09:55:46.190 回答
2

如果您remote: true的表单中有,控制器检测到的格式将是 format.js,它不会出现在您的成功@store.save部分中。

2个选项:

  • 默认为普通表单提交(通过删除remote: true
  • format.js通过添加就像在 else 子句中一样加载另一个 js.erb 文件,然后通过一些 javascript 在那里进行错误处理。
于 2016-01-29T05:25:07.843 回答