Devise和stored_location_for:你如何存储返回位置?

时间:2011-05-17 08:14:03

标签: ruby-on-rails-3 redirect devise

我有一个页面的路径是(例如)/ premises / 92我正在显示“请[登录]或[注册]以获取更多信息”如果用户没有登录,我想要设计用户登录后返回相同/ premises / 92页面。

我已阅读其他帖子,我想我明白设计stored_location_for应该如何运作。从理论上讲,我可以在ApplicationController

中加入类似的内容
def stored_location_for(resource)
  if (r = session[:return_to])
    session[:return_to] = nil
    r
  else
    super
  end
end

我的问题是:我如何/在哪里设置会话[:return_to]?

我只想在用户点击[登录]或[注册]时设置会话[:return_to],但最好的方法是什么?

  • 用JavaScript装饰链接?这可行,但似乎很苛刻。
  • 在呈现页面之前在Premises Controller中设置它?这似乎不正确:如果用户没有点击[登录]或[注册]链接怎么办?然后我将session [:return_to]设置为某个奇数值,如果用户从其他页面登录,可能会让我失望。
  • 在[登录]和[注册]链接中添加?return_to=/premises/92查询字符串,并在RegistrationsController和SessionsController中检测并使用该信息设置会话[:return_to]?这似乎有用,但也很苛刻。

这些都闻不对劲。什么是为stored_location_for设置状态的普遍接受的技术?

5 个答案:

答案 0 :(得分:25)

设计使用

session["#{scope}_return_to"]

如果您的身份验证模型是User,那么您可以使用session["user_return_to"]

答案 1 :(得分:8)

我发现整个设计重定向的东西很混乱。

@rorra表示Devise使用session["#{scope}_return_to"],他表示Devise默认after_sign_in_path_for(resource)将通过方法stored_location_for(resource)使用该变量。

因此,您应该将要存储的位置保存在变量session["#{scope}_return_to"]中,该变量通常为session["user_return_to"]。为此,请将以下内容放在application_controller.rb中:

after_action :store_location

def store_location
  # store last url - this is needed for post-login redirect to whatever the user last visited.
  if (request.fullpath != "/users/sign_in" &&
      request.fullpath != "/users/sign_up" &&
      request.fullpath != "/users/password" &&
      request.fullpath != "/users/sign_out" &&
      !request.xhr?) # don't store ajax calls
    session["user_return_to"] = request.fullpath 
  end
end

在某些情况下,您不需要定义after_sign_in_path_for(resource)方法,因为设计的默认方法将为您执行所有重定向,如果它们没有可用的重定向URL,您将被重定向到资源根路径(通常是用户)根路径)如果不存在,您将被重定向到根路径。但是,如果没有可用的重定向网址,您希望自定义用户的发送位置,请将以下内容添加到您的application_contorller.rb(并相应地更改root_path):

def after_sign_in_path_for(resource)
  stored_location_for(resource) || root_path
end

答案 2 :(得分:6)

Devise在会话中查找密钥"#{resource}_return_to"

我在这里引用API:

  

默认情况下,它首先尝试在中找到有效的#{resource}_return_to密钥   会话,然后它回退到#{resource}_root_path,否则它   使用root_path

Here is the link to the API

答案 3 :(得分:4)

这是我能想到的最好的。与facebook身份验证完美配合。通过在会话变量的前缀中添加更多限制,您可以删除越来越多的用户也不希望用户返回的路径(例如回调,启动页面,登录页面等)

#ApplicationsController

after_filter :store_location

def store_location
  session[:previous_urls] ||= []
  # store unique urls only
  session[:previous_urls].prepend request.fullpath if session[:previous_urls].first != request.fullpath && request.fullpath != "/user" && request.fullpath != "/user/login" && request.fullpath != "/" && request.fullpath != "/user/logout" && request.fullpath != "/user/join" && request.fullpath != "/user/auth/facebook/callback"
  # For Rails < 3.2
  # session[:previous_urls].unshift request.fullpath if session[:previous_urls].first != request.fullpath 
  session[:previous_urls].pop if session[:previous_urls].count > 3
end

def after_sign_in_path_for(resource) 
  @url = session[:previous_urls].reverse.first
  if @url != nil
    "http://www.google.com" + @url
  else
    root_path
  end
end

答案 4 :(得分:1)

我喜欢这个:

class ApplicationController < AC::Base
  after_filter :clear_attached_unit # UPDATED

  protected
  def clear_attached_unit
    session[:attached_unit_path] = nil unless keep_attached_unit_path?
  end

  def keep_attached_unit_path? # UPDATED
    @keep_attached_unit_path   
  end                           
end


class UnitController < ApplicationController
  before_filter :attach_unit, :only => [:show]

  protected
  def attach_unit
    session[:attached_unit_path] = request.url if request.get? && !request.xhr?
  end
end

class SessionsController < Devise::SessionsController
  before_filter :keep_attached_unit_path! # UPDATED

  protected
  def keep_attached_unit_path! # UPDATED
    @keep_attached_unit_path = true
  end

  def after_sign_in_path_for(resource_or_scope)
    if resource_or_scope.is_a?(User) && session[:attached_unit_path].present?
      session[:attached_unit_path]
    else
      super
    end
  end 
end

并将其提取到模块。