rails:当交叉控制器时,session是nilClass

时间:2015-10-21 03:21:01

标签: ruby-on-rails session

这是代码,在session_store.rb

Rails.application.config.session_store :cookie_store, key: '_blog_session'.

我使用cookie_store。

class HouseController < ApplicationController
  def browser
        session[:go_controller] = "house"
        session[:go_action] = "browser"
        @house=House.last
  end
class HouseController < ApplicationController
  def browser
        session[:go_controller] = "house"
        session[:go_action] = "browser"
        @house=House.last
  end

  def commercial
        session[:current_user_id] = nil
  end

  def rent
        session[:current_user_id] = "chendong"
        @house=House.last
  end

  def search

  end

end
在House Controller中,我可以在商业和租借行动中正确设置会话。

class UserController < ApplicationController
        def sell
                if session[:current_user_id] == nil  then
                        session[:go_controller] = "user"
                        session[:go_action] = "sell"
                        redirect_to controller:"user", action:"session"
                end
        end

但是在另一个控制器(在相同的rails应用程序中),在卖出动作中,session是一个nilClass。因为当我单击House控制器租借操作来设置session[:current_user_id]然后单击用户控制器销售操作时,会发生错误

undefined method `[]' for nil:NilClass

在行

if session[:current_user_id] == nil  then 

1 个答案:

答案 0 :(得分:1)

首先关闭。不要在整个控制器中传播您的身份验证逻辑。这是一场等待发生的灾难。例如,不要滥用会话进行分页。主要使用查询参数 - 其次是会话!

class SessionsHelper
  def sign_in!(user)
    reset_session
    session[:current_user_id] = user.id
  end

  def sign_out!
    reset_session
  end

  # @return [User|Nil]
  def current_user
    @user ||= User.find(session[:current_user_id])
  end

  def signed_in?
    !current_user.nil?
  end

  def is_signed_in?(user)
     user == current_user
  end
end

更好的方法是使用Warden在Rack层上执行此操作。 然后我们想要将这些方法添加到我们所有的控制器中:

class ApplicationController < ActionController::Base
  include SessionsHelper
end

我们现在可以重构我们的控制器:

class UserController < ApplicationController
  def sell
    unless current_user
      redirect_to controller: "user", action: "session"
    end
  end
end

但我们还没有完成!我们应该处理用户未以更好的方式进行身份验证时发生的情况:

class User < ActiveRecord::Base
  # ...
  class NotAuthenticated < StandardError; end
end
class ApplicationController < ActiveRecord::Base

   include SessionsHelper
   before_action :authenticate!

   rescue_from User::NotAuthenticated, with: :deny_access

   private 
     def authenticate!
       raise User::NotAuthenticated unless signed_in?
     end

     def deny_access
       redirect_to controller: "user", action: "session" 
     end
end 

您可能会注意到我们正在破坏所有内容,因为现在每个控制器操作都需要用户登录!但是使用选择退出安全性是一种很好的做法,因为它可以消除您因遗漏而无法保护的路径。

因此,您可以使用skip_before_action :authenticate!, only: [:index]来允许控制器中的索引操作。

一句忠告。

Good Rails应用程序构建在REST上,您可以在其中拥有资源,并且您通常可以使用传统的CRUD操作(显示,索引,创建,编辑,更新,销毁)作用于资源。你很少需要额外的行动。

不要试图把所有东西塞进有限的控制器中! Do-all控制器是一个非常糟糕的模式。

这是RESTful应用布局的一个示例:

Rails.application.routes.draw do
  resource :session, only: [:new, :create, :destroy]
  resources :users
  resources :houses do
    resources :bids
  end
end

运行$ rake routes以查看路线布局。