Następująca attempt_login
metoda jest wywoływana przy użyciu Ajax po przesłaniu formularza logowania.
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
Problem w tym, że redirect_to
to nie działa.
Jak byś to rozwiązał?
ruby-on-rails
ajax
ruby-on-rails-3
redirect
Misha Moroshko
źródło
źródło
render :js => "window.location = '#{jobs_path}'"
jobs_path
zasadzie nie jest tak sztywny jak adres URL? Jeśli adres URL ulegnie zmianie, zmieni się także nazwa trasy, chyba że jesteś bardzo ostrożny. Inną alternatywą byłobyrender js: "window.location = '#{polymorphic_path(@job.class)}'"
skorzystanie z obliczonej, pomysłowej trasy opartej na modelu zadania. Działa to tylko wtedy, gdy trasy są pomysłowe i używają standardowych konwencji nazewnictwa, które są zgodne z modelami. (Lub jeśli określisz model_name na swoich modelach, aby generowały prawidłowe nazwy tras.)Istnieje bardzo łatwy sposób na zachowanie pamięci flash do następnego żądania. W swoim kontrolerze zrób coś takiego
flash[:notice] = 'Your work was awesome! A unicorn is born!' flash.keep(:notice) render js: "window.location = '#{root_path}'"
flash.keep
Będzie upewnić się, że lampa jest przechowywane przez następne żądanie. Więc kiedyroot_path
jest renderowany, pokaże podany komunikat flash. Szyny są super :)źródło
Myślę, że to jest trochę przyjemniejsze:
render js: "window.location.pathname='#{jobs_path}'"
źródło
render js: "window.location.pathname = #{jobs_path.to_json}"
W jednej z moich aplikacji używam JSON do przenoszenia danych przekierowania i wiadomości flash. Wyglądałoby to mniej więcej tak:
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
Prosty przykład jQuery to:
$.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. } })
źródło
Połączenie najlepszych ze wszystkich odpowiedzi:
... 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 ...
źródło
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
źródło
Nie chciałem modyfikować moich działań kontrolera, więc wymyśliłem ten 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
źródło