Доступ к current_user в модели - PullRequest
38 голосов
/ 25 марта 2010

у меня 3 стола

items (columns are:  name , type)
history(columns are: date, username, item_id)
user(username, password)

Когда пользователь говорит «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

Мой метод входа в систему в 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

Я не использую какой-либо плагин аутентификации. Буду признателен, если кто-нибудь скажет мне, как этого добиться, не используя плагин (например, метку пользователя и т. Д.), Если это возможно.

Ответы [ 7 ]

74 голосов
/ 25 марта 2010

Рельсы 5

Объявить модуль

module Current
  thread_mattr_accessor :user
end

Назначить текущего пользователя

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

Теперь вы можете ссылаться на текущего пользователя как Current.user

Документация о thread_mattr_accessor

Рельсы 3,4

Доступ к 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

Установите атрибут current_user в around_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

Установите 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

Наконец, обратитесь к current_user в update_history из 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
50 голосов
/ 03 октября 2012

Контроллер должен сообщить экземпляру модели

Работа с базой данных - работа модели. Обработка веб-запросов, включая знание пользователя для текущего запроса, является задачей контроллера.

Поэтому, если экземпляру модели необходимо знать текущего пользователя, контроллер должен сообщить ему.

def create
  @item = Item.new
  @item.current_user = current_user # or whatever your controller method is
  ...
end

Предполагается, что Item имеет attr_accessor для current_user.

6 голосов
/ 25 марта 2010

Если пользователь создает элемент, не должен ли он иметь предложение belongs_to :user? Это позволит вам в вашем after_update сделать

History.create :username => self.user.username
1 голос
/ 07 июня 2013

Вы можете написать вокруг_фильтра в ApplicationController

around_filter :apply_scope 

def apply_scope 

  Document.where(:user_id => current_user.id).scoping do 
  yield 

end 
0 голосов
/ 23 августа 2018

В Rails 5.2 для глобального доступа к пользователю и другим атрибутам используется следующий подход: CurrentAttributes .

0 голосов
/ 03 июля 2018

Это можно легко сделать за несколько шагов, внедрив Thread.

Шаг 1:

class User < ApplicationRecord

  def self.current
    Thread.current[:user]
  end

  def self.current=(user)
    Thread.current[:user] = user
  end

end

Шаг 2:

class ApplicationController < ActionController::Base
  before_filter :set_current_user

  def set_current_user
    User.current = current_user
  end
end

Теперь вы можете легко получить текущего пользователя как User.current

.
0 голосов
/ 05 января 2016

Трюк Thread не является поточно-ориентированным, по иронии судьбы.

Мое решение состояло в том, чтобы пройтись назад по стеку в поисках кадра, отвечающего current_user. Если ничего не найдено, возвращается ноль. Пример:

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

Это можно сделать более надежным, подтвердив ожидаемый тип возврата, и, возможно, подтвердив, что владельцем кадра является тип контроллера ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...