设计和处理闪光灯

pin*_*ngu 5 flash ruby-on-rails devise

我正在使用带有rails 3的Devise 3.1.1,我在我的布局中有这个flash处理代码:

<% flash.each do |name, msg| %>
    <%= content_tag :section, msg, :id => "flash_#{name}", :class => "flash" %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

我登录我的应用程序,flash说:

"Signed in successfully."
Run Code Online (Sandbox Code Playgroud)

然后退出,然后登录不正确,闪光说:

"Signed out successfully."
"Invalid email or password."
Run Code Online (Sandbox Code Playgroud)

我想我理解为什么我收到两条消息,当登录错误时没有重定向,只有渲染.

不知道怎么解决它.

Bil*_*han 24

我弄明白了原因.

当你深入研究Devise的SessionsController源代码时,你会发现#create如下方法:

# POST /resource/sign_in
def create
  self.resource = warden.authenticate!(auth_options)
  set_flash_message(:notice, :signed_in) if is_navigational_format?
  sign_in(resource_name, resource)
  respond_with resource, :location => after_sign_in_path_for(resource)
end
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,Devise设置flash消息以便在此处签名成功.这就是你所看到的信息"Signed in successfully.".它使用的方法set_flash_message只是一个包装flash[key]= "something".对于#destroy向您展示的方法也是如此"Signed out successfully".

请注意,在上面的代码中,没有代码可以设置错误消息,例如"密码或电子邮件无效".那你怎么看到这个消息呢?它设置在Devise::FailureApp

def recall
  env["PATH_INFO"]  = attempted_path
  flash.now[:alert] = i18n_message(:invalid)
  self.response = recall_app(warden_options[:recall]).call(env)
end
Run Code Online (Sandbox Code Playgroud)

注意这里,方法是flash.now,而不是flash.不同之处是flash.now在当前请求中提供flash消息,而不是下一个.

默认情况下,向Flash添加值将使它们可用于下一个请求,但有时您可能希望在同一请求中访问这些值.例如,如果创建操作无法保存资源并且您直接呈现新模板,则不会产生新请求,但您可能仍希望使用闪存显示消息.为此,您可以像使用普通闪存一样使用flash.now.http://guides.rubyonrails.org/action_controller_overview.html#the-flash

所以原因现在揭晓了.

  1. 你退出了.你打了SessionsController#destroy.设计破坏了您的会话,带您进入/users/sign_in,'new再次为您的登录呈现模板.flash对象包含已成功注销的消息,您可以看到它.

  2. 现在您尝试在同一页面中登录.这次你的表单提交了#create.如果出现错误,Devise不会将您重定向到任何地方,而是'new'使用flash.now包含登录错误消息的对象再次呈现相同的模板.

在步骤2中,由于未呈现新请求,因此未删除最后一个Flash对象,但flash.now添加了另一个新对象.所以你看到两条消息.

当然可以覆盖Devise来改变这种行为,但这很麻烦且不必要.

更方便和用户友好的解决方案是,登录或退出后,不要让用户登录页面.

这是很容易设置store_location和覆盖after_sign_in_path_for,并after_signed_out_path_for在您的应用程序控制器.

def store_location
  disable_pattern = /\/users/
  session[:previous_url] = request.fullpath unless request.fullpath =~ disable_pattern
end

def after_sign_in_path_for(resource)
  session[:previous_url] || root_path
end

def after_sign_out_path_for(resource)
  after_sign_in_path_for(resource)
end
Run Code Online (Sandbox Code Playgroud)

通过此设置,用户将在登录或退出后登陆其先前浏览的页面,并且他们将不再在问题中看到两个Flash消息.

原因是,当用户退出时,他将重定向到上一页并看到已注销的消息.当他想登录时,他需要登录页面这是一个新请求,然后将删除之前退出的闪存.