Ruby-on-rails Rails 3:如何在 Ajax 调用中“redirect_to”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5454806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:47:57  来源:igfitidea点击:

Rails 3: How to "redirect_to" in Ajax call?

ruby-on-railsajaxruby-on-rails-3redirect

提问by Misha Moroshko

The following attempt_loginmethod is called using Ajax after a login form is submitted.

attempt_login提交登录表单后,使用 Ajax 调用以下方法。

class AccessController < ApplicationController
  [...]
  def attempt_login
    authorized_user = User.authenticate(params[:username], params[:password])

    if authorized_user
      session[:user_id] = authorized_user.id
      session[:username] = authorized_user.username
      flash[:notice] = "Hello #{authorized_user.name}."
      redirect_to(:controller => 'jobs', :action => 'index')
    else
      [...]
    end
  end
end

The problem is that redirect_todoesn't work.

问题是这redirect_to行不通。

How would you solve this ?

你会如何解决这个问题?

回答by Misha Moroshko

Finally, I just replaced

最后,我只是更换

redirect_to(:controller => 'jobs', :action => 'index')

with this:

有了这个:

render :js => "window.location = '/jobs/index'"

and it works fine!

它工作正常!

回答by nathanvda

There is very easy way to keep the flash for the next request. In your controller do something like

有一种非常简单的方法可以为下一个请求保留闪存。在你的控制器中做类似的事情

flash[:notice] = 'Your work was awesome! A unicorn is born!'
flash.keep(:notice)
render js: "window.location = '#{root_path}'"

The flash.keepwill make sure the flash is kept for the next request. So when the root_pathis rendered, it will show the given flash message. Rails is awesome :)

flash.keep将确保闪光灯不停地为下一个请求。所以当root_path被渲染时,它会显示给定的 flash 消息。Rails 很棒:)

回答by Mike

I think this is slightly nicer:

我认为这稍微好一点:

render js: "window.location.pathname='#{jobs_path}'"

render js: "window.location.pathname='#{jobs_path}'"

回答by Priit

In one of my apps, i use JSON to carry on the redirect and flash message data. It would look something like this:

在我的一个应用程序中,我使用 JSON 来进行重定向和闪现消息数据。它看起来像这样:

class AccessController < ApplicationController
  ...
  def attempt_login
    ...
    if authorized_user
      if request.xhr?
        render :json => {
          :location => url_for(:controller => 'jobs', :action => 'index'),
          :flash => {:notice => "Hello #{authorized_user.name}."}
        }
      else
        redirect_to(:controller => 'jobs', :action => 'index')
      end
    else
      # Render login screen with 422 error code
      render :login, :status => :unprocessable_entity
    end
  end
end

And simple jQuery example would be:

简单的 jQuery 示例是:

$.ajax({
  ...
  type: 'json',
  success: functon(data) {
    data = $.parseJSON(data);
    if (data.location) {
      window.location.href = data.location;
    }
    if (data.flash && data.flash.notice) {
      // Maybe display flash message, etc.
    }
  },
  error: function() {
    // If login fails, sending 422 error code sends you here.
  }
})

回答by Yarin

Combining the best of all answers:

结合所有答案中最好的:

...
if request.xhr?
  flash[:notice] = "Hello #{authorized_user.name}."
  flash.keep(:notice) # Keep flash notice around for the redirect.
  render :js => "window.location = #{jobs_path.to_json}"
else
...

回答by OlegZ

def redirect_to(options = {}, response_status = {})
  super(options, response_status)
  if request.xhr?
    # empty to prevent render duplication exception
    self.status = nil
    self.response_body = nil
    path = location
    self.location = nil

    render :js => "window.location = #{path.to_json}"
  end
end

回答by Macario

I didn't want to modify my controller actions so I came up with this hack:

我不想修改我的控制器动作,所以我想出了这个黑客:

class ApplicationController < ActionController::Base
  def redirect_to options = {}, response_status = {}
    super

    if request.xhr?
      self.status        = 200
      self.response_body = "<html><body><script>window.location.replace('#{location}')</script></body></html>"
    end
  end
end