Ruby-on-rails 在模型中访问 current_user
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2513383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Access current_user in model
提问by LearnRails
I have 3 tables
我有3张桌子
items (columns are: name , type)
history(columns are: date, username, item_id)
user(username, password)
When a user say "ABC" logs in and creates a new item, a history record gets created with the following after_create filter. How to assign this username ‘ABC' to the username field in history table through this filter.
当用户说“ABC”登录并创建新项目时,将使用以下 after_create 过滤器创建历史记录。如何通过此过滤器将此用户名“ABC”分配给历史记录表中的用户名字段。
class Item < ActiveRecord::Base
has_many :histories
after_create :update_history
def update_history
histories.create(:date=>Time.now, username=> ?)
end
end
My login method in session_controller
我在 session_controller 中的登录方法
def login
if request.post?
user=User.authenticate(params[:username])
if user
session[:user_id] =user.id
redirect_to( :action=>'home')
flash[:message] = "Successfully logged in "
else
flash[:notice] = "Incorrect user/password combination"
redirect_to(:action=>"login")
end
end
end
I am not using any authentication plugin. I would appreciate if someone could tell me how to achieve this without using plugin(like userstamp etc.) if possible.
我没有使用任何身份验证插件。如果可能的话,如果有人能告诉我如何在不使用插件(如 userstamp 等)的情况下实现这一点,我将不胜感激。
回答by Harish Shetty
Rails 5
导轨 5
Declare a module
声明一个模块
module Current
thread_mattr_accessor :user
end
Assign the current user
分配当前用户
class ApplicationController < ActionController::Base
around_action :set_current_user
def set_current_user
Current.user = current_user
yield
ensure
# to address the thread variable leak issues in Puma/Thin webserver
Current.user = nil
end
end
Now you can refer to the current user as Current.user
现在您可以将当前用户称为 Current.user
Documentation about thread_mattr_accessor
Rails 3,4
导轨 3,4
It is not a common practice to access the current_userwithin a model. That being said, here is a solution:
访问current_user模型内的不是一种常见的做法。话虽如此,这是一个解决方案:
class User < ActiveRecord::Base
def self.current
Thread.current[:current_user]
end
def self.current=(usr)
Thread.current[:current_user] = usr
end
end
Set the current_userattribute in a around_filterof ApplicationController.
current_user在 aaround_filter中设置属性ApplicationController。
class ApplicationController < ActionController::Base
around_filter :set_current_user
def set_current_user
User.current = User.find_by_id(session[:user_id])
yield
ensure
# to address the thread variable leak issues in Puma/Thin webserver
User.current = nil
end
end
Set the current_userafter successful authentication:
设置current_user认证成功后:
def login
if User.current=User.authenticate(params[:username], params[:password])
session[:user_id] = User.current.id
flash[:message] = "Successfully logged in "
redirect_to( :action=>'home')
else
flash[:notice] = "Incorrect user/password combination"
redirect_to(:action=>"login")
end
end
Finally, refer to the current_userin update_historyof Item.
最后,参考current_userin update_historyof Item。
class Item < ActiveRecord::Base
has_many :histories
after_create :update_history
def update_history
histories.create(:date=>Time.now, :username=> User.current.username)
end
end
回答by Nathan Long
The Controller should tell the model instance
控制器应该告诉模型实例
Working with the database is the model's job. Handling web requests, including knowing the user for the current request, is the controller's job.
使用数据库是模型的工作。处理 Web 请求,包括了解当前请求的用户,是控制器的工作。
Therefore, if a model instance needs to know the current user, a controller should tell it.
因此,如果模型实例需要知道当前用户,控制器应该告诉它。
def create
@item = Item.new
@item.current_user = current_user # or whatever your controller method is
...
end
This assumes that Itemhas an attr_accessorfor current_user.
这假设Item有一个attr_accessorfor current_user。
回答by Faisal
If the user creates an item, shouldn't the item have a belongs_to :userclause? This would allow you in your after_updateto do
如果用户创建了一个项目,该项目不应该有一个belongs_to :user子句吗?这将允许你在你after_update做
History.create :username => self.user.username
回答by murb
The Rails 5.2 approach for having global access to the user and other attributes is CurrentAttributes.
对用户和其他属性进行全局访问的 Rails 5.2 方法是CurrentAttributes。
回答by Harshit Agarwal
This can be done easily in few steps by implementing Thread.
通过实现 Thread,这可以通过几个步骤轻松完成。
Step 1:
第1步:
class User < ApplicationRecord
def self.current
Thread.current[:user]
end
def self.current=(user)
Thread.current[:user] = user
end
end
Step 2:
第2步:
class ApplicationController < ActionController::Base
before_filter :set_current_user
def set_current_user
User.current = current_user
end
end
Now you can easily get current user as User.current
现在您可以轻松地将当前用户作为 User.current
回答by John Moore
You could write an around_filter in ApplicationController
你可以在 ApplicationController 中写一个 around_filter
around_filter :apply_scope
def apply_scope
Document.where(:user_id => current_user.id).scoping do
yield
end
回答by keredson
The Threadtrick isn't threadsafe, ironically.
Thread讽刺的是,这个技巧不是线程安全的。
My solution was to walk the stack backwards looking for a frame that responds to current_user. If none is found it returns nil. Example:
我的解决方案是向后遍历堆栈以寻找响应current_user. 如果没有找到,则返回 nil。例子:
def find_current_user
(1..Kernel.caller.length).each do |n|
RubyVM::DebugInspector.open do |i|
current_user = eval "current_user rescue nil", i.frame_binding(n)
return current_user unless current_user.nil?
end
end
return nil
end
It could be made more robust by confirming the expected return type, and possibly by confirming owner of the frame is a type of controller...
通过确认预期的返回类型,并可能通过确认框架的所有者是一种控制器,它可以变得更加健壮......

