46 votes

Rails 3 devise, current_user n'est pas accessible dans un Model ?

Dans mon modèle project.rb, j'essaie de créer un scope avec une variable dynamique :

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

J'obtiens l'erreur suivante : "variable locale ou méthode non définie `current_user' pour #"

Où dans le contrôleur je peux accéder à current_user.instance_id... Y a-t-il une raison pour laquelle le modèle ne peut pas y accéder et un moyen d'y parvenir ? De plus, est-ce le bon endroit pour créer une portée comme celle ci-dessus, ou est-ce que cela appartient au contrôleur ?

Merci

73voto

mdrozdziel Points 2629

Cela n'a pas beaucoup de sens, comme vous l'avez déjà souligné. L'utilisateur actuel n'appartient pas du tout à la logique du modèle, il devrait être géré au niveau du contrôleur.

Mais vous pouvez toujours créer une portée comme ça, il suffit de lui passer le paramètre à partir du 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)

32voto

Michał Szajbe Points 4022

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 truc.

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

Cette méthode fonctionne comme prévu, mais elle peut être considérée comme sale, car nous définissons essentiellement une variable globale ici.

8voto

Lumbee Points 1216

Ryan Bates propose un moyen assez sûr de mettre en œuvre ce type de stratégie. dans cette émission ferroviaire

Cet épisode est payant (ne votez pas contre moi !) mais vous pouvez parcourir le code source gratuitement

Ici, il crée un current_tenant mais vous pouvez facilement remplacer la méthode current_user à la place.

Voici les principaux éléments 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) }

0voto

sampi Points 557

Vous n'avez pas besoin d'utiliser des scopes. 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X