2010-09-18 2 views
45

в моей project.rb модели, я пытаюсь создать область с динамической переменной:Rails 3 devise, current_user недоступен в модели?

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 ... Есть ли причина, по которой модель не может получить к ней доступ и как получить доступ? Кроме того, это подходящее место для создания области, как указано выше, или же это принадлежит контроллеру?

ответ

71

Это не имеет большого смысла, как вы уже указали. Current_user вообще не относится к логике модели, его следует обрабатывать на уровне контроллера.

Но вы можете создать сферу, как это, просто передать параметр к нему от контроллера:

scope :instanceprojects, lambda { |user| 
    where("projects.instance_id = ?", user.instance_id) 
} 

Теперь вы можете вызвать его в контроллере:

Model.instanceprojects(current_user) 
+1

Это замечательно. попробовав это сейчас – AnApprentice

+0

Работал отлично. Спасибо! – AnApprentice

+7

Я назвал область видимости «так», чтобы она хорошо читала. 'Project.of current_user' – romeroabelleira

27

Уже принят ответ обеспечивает действительно правильный способ достижения этого.

Но вот нить-безопасная версия 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 

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

+2

Спасибо. У меня была конкретная ситуация, когда я действительно нуждался в этом и не имел возможности передать его. Кстати, этот код содержит несколько ошибок - вы должны использовать пользователя.current_user = метод от ApplicationController (в противном случае, зачем он это сделал), а также он установлен в: current_user, но читатель читает: user (Мне хотелось долго видеть это!) – Jords

+0

Спасибо, что указали это. Ответ обновлен. –

+0

Я пробовал это и отлично работает. Однако в моей среде разработки нет ситуации с несколькими пользователями. Я обеспокоен комментариями в других ответах о проблеме с потоковой безопасностью. Кто-нибудь еще проверил это в производственной среде? Ура! –

8

Ryan Bates выкладывает довольно безопасный способ реализации такой стратегии in this railscast

Это платный эпизод (не вниз голосовать меня!), Но вы можете browse the source code for free

Здесь он создает метод 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) } 
0

Вам не нужно использовать областей. Если вы установили соответствующие ассоциации в моделях, следующая часть кода, размещенная в контроллере, должна сделать трюк:

@projects = current_user.instance.projects 
Смежные вопросы