有没有办法检查rails是否设置了永久性cookie?

时间:2011-08-16 14:37:16

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

我正在使用TestUnit,我想测试记住我的功能(当用户登录时)。

cookies变量(以及还需要/ response .cookies)仅包含没有过期时间的cookie值。

Rails以某种方式告诉网络浏览器什么时候cookie应该过期,所以我认为必须有办法检查cookie过期时间。

修改

test "set permanent cookie" do
  post :create, email: 'email', password: 'password', remember_me: true
  # cookies[:auth_token] = random_string
  # @request.cookies[:auth_token] = also_random_string
  # @response.cookies[:auth_token] = also_random_string
end

问题是我只能得到cookie的值,而不能得到包含过期时间的哈希值。

2 个答案:

答案 0 :(得分:4)

正如您所注意到的,cookies Hash只包含post调用后检查它的值(而不是到期时间)(这至少是Rails 2.3以来的行为)

您有两种选择:

首先,您可以检查response.headers["Set-Cookie"]项目。它将包括那里的到期时间。但是,Set-Cookie值只是一个字符串,您需要解析它。例如,cookies["foo"] = {:value => "bar", :expires => Time.now + 10.years }会给你:

response.headers["Set-Cookie"]
# => "foo=bar; path=/; expires=Mon, 16-Aug-2021 21:54:30 GMT"

另一个选项(取自This Question/Answer)将存储cookie jar并确保它发送expires值:

stub_cookie_jar = HashWithIndifferentAccess.new
controller.stub(:cookies) { stub_cookie_jar }
post :create, email: 'email', password: 'password', remember_me: true
expiring_cookie = stub_cookie_jar['expiring_cookie']
expiring_cookie[:expires].to_i.should be_within(1).of(1.hour.from_now.to_i)

答案 1 :(得分:2)

不幸的是,我无法在@ DylanMarkow的答案中找到或链接的解决方案,所以这里是我在检查“记住我”复选框时测试“永久”cookie的设置(测试受到影响/公然)从Test::Unit tests that DHH made in the commit that added cookies.permanent to Rails复制。

测试使用RSpecFactoryGirl

<强>规格/请求/ authentication_requests_spec.rb

require 'spec_helper'

describe "Authentication Requests" do
  # ...
  describe "authorization" do
    # ...
    describe "cookies" do
      let(:user) { FactoryGirl.create(:user) }

      subject { response.headers["Set-Cookie"] }

      context "when remember me is set" do
        before { sign_in_request(user) }
        it { should =~ %r(.+expires.+#{20.years.from_now.year}) }
      end

      context "when remember me is not set" do
        before { sign_in_request(user, remember_me: false) }
        it { should_not =~ %r(expires) }
      end
    end
  end
end

<强>规格/ utilities.rb

def sign_in_request(user, remember_me: "true")
  post session_path(
    session: {
      email: user.email,
      password: user.password,
      remember_me: remember_me
    }
  )
end

以下应用代码段使用i18nHamlBootstrapSimple Form语法:

应用/视图/会话/ new.html.haml

= simple_form_for :session, url: session_path, html: {class: 'form-vertical' } do |f|
  = f.input :email
  = f.input :password
  .checkbox
    = f.input :remember_me, as: :boolean, label: false do
      = check_box_tag :remember_me, 1, true
      = label_tag :remember_me
  = f.submit t('.signin'), class: "btn btn-large btn-primary"

应用/控制器/ sessions_controller.rb

class SessionsController < ApplicationController
  # ...
  def create
    if user = User.authenticate(params[:session][:email],
                                params[:session][:password])
      sign_in user
      flash[:success] = t('flash.successful_signin')
      redirect_to root_url
    else
      flash.now[:error] = t('flash.invalid_credentials')
      render 'new'
    end
  end
  # ...
end

应用/模型/ user.rb

class User < ActiveRecord::Base
  has_secure_password
  # ...
  before_create :generate_authentication_token

  def self.authenticate(email, password)
    find_by_email(email).try(:authenticate, password)
  end

  private

    def generate_authentication_token
      begin
        self.authentication_token = SecureRandom.urlsafe_base64
      end while User.exists?(authentication_token: self.authentication_token)
    end
end

应用/控制器/ application_controller.rb

class ApplicationController < ActionController::Base
  # ...
  private

    # A cookie that does not have an expiry will automatically be expired by
    # the browser when browser's session is finished.
    # cookies.permanent sets the expiry to 20 years
    # Booleans seem to get passed from forms as strings
    def sign_in(user)
      if remember_me
        cookies.permanent[:authentication_token] = user.authentication_token
      else
        cookies[:authentication_token] = user.authentication_token
      end
      self.current_user = user
    end
    helper_method :sign_in

    def remember_me
      params[:session].try(:[], :remember_me) == "true" ||
        params[:remember_me] == "true"
    end
    # ...
end