O attempt_login
método a seguir é chamado usando Ajax depois que um formulário de login é enviado.
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
O problema é que redirect_to
isso não funciona.
Como você resolveria isso?
ruby-on-rails
ajax
ruby-on-rails-3
redirect
Misha Moroshko
fonte
fonte
render :js => "window.location = '#{jobs_path}'"
jobs_path
basicamente tão rígido quanto o URL? Se o URL mudar, o mesmo acontecerá com o nome da rota, a menos que você esteja sendo extremamente cuidadoso. Outra alternativa seriarender js: "window.location = '#{polymorphic_path(@job.class)}'"
usar a rota calculada com base no modelo de trabalho. Isso só funciona se suas rotas forem engenhosas e usarem convenções de nomenclatura padrão que se alinham com seus modelos. (Ou se você especificar model_name em seus modelos para que eles gerem os nomes de rota corretos.)Existe uma maneira muito fácil de guardar o flash para a próxima solicitação. Em seu controlador, faça algo como
flash[:notice] = 'Your work was awesome! A unicorn is born!' flash.keep(:notice) render js: "window.location = '#{root_path}'"
o
flash.keep
irá certificar-se o flash é mantido para o próximo pedido. Portanto, quando oroot_path
for renderizado, ele mostrará a mensagem flash fornecida. Rails é incrível :)fonte
Acho que é um pouco melhor:
render js: "window.location.pathname='#{jobs_path}'"
fonte
render js: "window.location.pathname = #{jobs_path.to_json}"
Em um dos meus aplicativos, eu uso JSON para realizar o redirecionamento e os dados de mensagem flash. Seria mais ou menos assim:
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
E um exemplo simples de jQuery seria:
$.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. } })
fonte
Combinando o melhor de todas as respostas:
... 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 ...
fonte
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
fonte
Eu não queria modificar as ações do meu controlador, então inventei este 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
fonte