Ruby-on-rails 在模型中访问 c​​urrent_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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:27:10  来源:igfitidea点击:

Access current_user in model

ruby-on-rails

提问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

关于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...

通过确认预期的返回类型,并可能通过确认框架的所有者是一种控制器,它可以变得更加健壮......