Rails respond_to重定向无法正常工作

时间:2016-01-29 05:21:54

标签: ruby-on-rails ajax respond-to

我的Rails应用程序中的创建控制器中的respond_to块没有重定向成功保存...我确定这是一个简单的解决方案,但我对Rails缺乏经验,这是我第一次我遇到了这个问题。

表单设置为:remote =>是的,控制器如下......

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 %>

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

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

2 个答案:

答案 0 :(得分:3)

remote: trueajax请求。

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不能&#34;重定向&#34; (独自)
  •   
  • Ajax在Rails控制器中将被视为JS
  •   
  • 你必须&#34; hack&#34;通过JS
  • 来实现它   

如果您没有使用Ajax的经验,那么简单的解释就是它是一个&#34;伪请求&#34 ;;它发送HTTP请求而无需重新加载浏览器。

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

你不能&#34;重定向&#34;除非你用javascript解析响应,否则通过Ajax。正如Ajax的缩写(Asynchronous Javascript和 XML )所示,响应应该是XML(IE没有功能)。

-

要回答您的问题,您需要使用flash.now作为&#34; flash&#34;消息,并使用您的.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 %>;

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 :(得分:2)

如果您的表单中有remote: true,则控制器检测到的格式为format.js,这在您的@store.save部分中不存在。

2个选项:

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