Rails 3 devise, current_user недоступен в модели?
в моей модели project.rb, я пытаюсь создать область с динамической переменной:
scope :instanceprojects, lambda {
where("projects.instance_id = ?", current_user.instance_id)
}
Я получаю следующую ошибку:
undefined local variable or method `current_user' for #<Class:0x102fe3af0>
Где в контроллере я могу получить доступ к current_user.instance_id
... Есть ли причина, по которой модель не может получить к ней доступ и как получить доступ? Кроме того, это подходящее место для создания области, как указано выше, или же она принадлежит контроллеру?
Ответы
Ответ 1
Это не имеет большого смысла, как вы уже указали. Current_user вообще не относится к логике модели, его следует обрабатывать на уровне контроллера.
Но вы все равно можете создать такую область, просто передайте ей параметр из контроллера:
scope :instanceprojects, lambda { |user|
where("projects.instance_id = ?", user.instance_id)
}
Теперь вы можете вызвать его в контроллере:
Model.instanceprojects(current_user)
Ответ 2
Уже принятый ответ обеспечивает действительно правильный способ достижения этого.
Но вот потокобезопасная версия трюка User.current_user
.
class User
class << self
def current_user=(user)
Thread.current[:current_user] = user
end
def current_user
Thread.current[:current_user]
end
end
end
class ApplicationController
before_filter :set_current_user
def set_current_user
User.current_user = current_user
end
end
Это работает так, как ожидалось, однако его можно считать грязным, потому что мы в основном определяем глобальную переменную здесь.
Ответ 3
Райан Бейтс предлагает довольно безопасный способ реализовать такую стратегию в этом railscast
Это платный эпизод (не голосуйте!), но вы можете бесплатно просмотреть исходный код
Здесь он создает метод current_tenant
, но вместо него вы можете легко заменить current_user
.
Вот ключевые бит кода...
#application_controller.rb
around_filter :scope_current_tenant
private
def current_tenant
Tenant.find_by_subdomain! request.subdomain
end
helper_method :current_tenant
def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
#models/tenant.rb
def self.current_id=(id)
Thread.current[:tenant_id] = id
end
def self.current_id
Thread.current[:tenant_id]
end
Тогда в модели вы можете сделать что-то вроде...
default_scope { where(tenant_id: Tenant.current_id) }
Ответ 4
Вам не нужно использовать области. Если вы установили соответствующие ассоциации в моделях, следующая часть кода, размещенная в контроллере, должна выполнить трюк:
@projects = current_user.instance.projects