dans mon modèle project.rb, j'essaie de créer une portée avec une variable dynamique:
scope :instanceprojects, lambda {
where("projects.instance_id = ?", current_user.instance_id)
}
Je reçois l'erreur suivante:
undefined local variable or method `current_user' for #<Class:0x102fe3af0>
Où dans le contrôleur je peux accéder à current_user.instance_id
... Y at-il une raison pour laquelle le modèle ne peut pas y accéder et un moyen d’y accéder? En outre, est-ce le bon endroit pour créer une étendue comme celle ci-dessus, ou est-ce que cela appartient au contrôleur?
Cela n'a pas beaucoup de sens, comme vous l'avez déjà souligné. Current_user n'appartient pas du tout à la logique de modèle, elle devrait être gérée au niveau du contrôleur.
Mais vous pouvez toujours créer une telle portée, il suffit de lui transmettre le paramètre depuis le contrôleur:
scope :instanceprojects, lambda { |user|
where("projects.instance_id = ?", user.instance_id)
}
Maintenant, vous pouvez l'appeler dans le contrôleur:
Model.instanceprojects(current_user)
La réponse déjà acceptée fournit un moyen vraiment correct d'y parvenir.
Mais voici la version thread-safe de User.current_user
astuce.
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
Cela fonctionne comme prévu, mais cela peut être considéré comme sale, car nous définissons ici une variable globale.
Ryan Bates propose un moyen plutôt sûr de mettre en œuvre ce type de stratégie dans cette diffusion sur rail
C'est un épisode payé (ne me votez pas, mais vous pouvez parcourir le code source gratuitement
Ici, il crée une méthode current_tenant
, mais vous pouvez facilement remplacer current_user
à la place.
Voici les éléments clés du code ...
#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
Ensuite, dans le modèle, vous pouvez faire quelque chose comme ...
default_scope { where(tenant_id: Tenant.current_id) }
Vous n'avez pas besoin d'utiliser des portées. Si vous avez défini les associations appropriées dans les modèles, le morceau de code suivant placé dans le contrôleur devrait faire l'affaire:
@projects = current_user.instance.projects