关于ajax:Rails respond_to重定向无法正常工作

Rails respond_to redirect not working

在我的Rails应用程序中,创建控制器中的响应块没有在成功保存时重定向…我相信这是一个简单的解决方案,但是我对Rails没有经验,这是我第一次遇到这个问题。

窗体设置为:remote=>true,控制器如下…

1
2
3
4
5
6
7
8
9
10
11
12
13
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

在主题上,条件的其他部分的代码也不会运行,除了format.js {},它确实运行了create.js.erb文件中的代码(暂时是一个警报)。

我正在使用Rails 4.2.5。有人能帮助我理解为什么重定向和警报不起作用吗?谢谢您!

编辑以显示解决方案基于Rich的回答,我提出了以下解决方案:

控制器:

1
2
3
4
5
6
7
8
9
10
11
12
13
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

J.S.Erb

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

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

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


remote: true是一个Ajax请求。

Ajax是javascript,因此将调用format.js方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 cannot"redirect" (on its own)
  • Ajax will be treated as JS in your Rails controller
  • You have to"hack" the flash to get it working through JS

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

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

除非用JavaScript解析响应,否则不能通过Ajax"重定向"。正如Ajax首字母缩略词(Asynchronous javascript和XML)所暗示的,响应应该是XML(即没有功能)。

——

要回答您的问题,您需要使用flash.now作为"flash"消息,并使用.js.erb文件处理响应:

1
2
3
4
5
6
7
8
9
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

这样你就可以打电话给…

1
2
3
#app/views/stores/create.js.erb
<% if flash.now[:alert] %> alert("<%=j flash.now[:alert] %>"); <% end %>
window.location.href = <%= root_url %>;

裁判

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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

如果你想更多地增加你的代码,你可以看看respondersgem:

1
2
3
4
5
6
7
8
9
#app/controllers/stores_controller.rb
class StoresController < ApplicationController
   respond_to :js, only: :create

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


如果您的表单中有remote: true,则控制器检测到的格式将为format.js,而在成功的@store.save部分中没有该格式。

2种选择:

  • 默认为正常形式提交(通过删除remote: true)
  • 通过添加format.js加载另一个js.erb文件,就像在else子句中一样,然后通过一些javascript在那里进行错误处理。