Question

J'ai un projet Rails 3. Avec Rails 3 est venu Arel et la possibilité de réutiliser une portée de construire une autre. Je me demande s'il y a un moyen d'utiliser des étendues lors de la définition d'une relation (par exemple un « has_many »).

Je les enregistrements qui ont des colonnes d'autorisation. Je voudrais construire une default_scope qui prend mes colonnes d'autorisation en considération afin que les dossiers (même ceux accessibles par une relation) sont filtrés.

À l'heure actuelle, dans Rails 3, default_scope (y compris les correctifs que j'ai trouvé) ne fournissent pas un moyen exploitable de passer un proc (dont j'ai besoin pour la variable la liaison tardive). Est-il possible de définir un has_many dans lequel un champ nommé peut être passé?

L'idée de la réutilisation d'un champ nommé ressemblerait à ceci:

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders

ou le codage implicitement que la portée du nom dans la relation ressemblerait à ceci:

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}

Je suis tout simplement essayer d'appliquer default_scope avec la liaison tardive. Je préférerais utiliser une approche Arel (si elle existe), mais utiliserais une option viable.

Depuis que je fais référence à l'utilisateur actuel, je ne peux pas compter sur des conditions qui ne sont pas évalués au dernier moment, par exemple:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
Était-ce utile?

La solution

Je vous suggère de jeter un oeil à "Named scopes sont morts "

L'auteur y explique la puissance Arel est:)

J'espère que ça vous aidera.

EDIT n ° 1 Mars 2014

Comme un état des commentaires, la différence est maintenant une question de goût personnel.

Cependant, je recommande personnellement toujours pour éviter d'exposer la portée de Arel à une couche supérieure (étant un contrôleur ou toute autre chose que l'accès aux modèles directement), et de faire, il faudrait:

  1. Créer un champ, et l'exposer à travers une méthode dans votre modèle. Cette méthode serait celle que vous exposez au contrôleur;
  2. Si vous n'exposez vos modèles à vos contrôleurs (vous avez une sorte de couche de service au-dessus d'eux), alors vous êtes bien. La couche anti-corruption est votre service et il peut accéder à votre portée modèle sans trop se soucier de la façon dont les étendues sont mises en œuvre.

Autres conseils

Que diriez-vous des extensions d'association?

class Item < ActiveRecord::Base
  has_many :orders do
    def for_user(user_id)
      where(user_id: user_id)
    end
  end
end

Item.first.orders.for_user(current_user)

Mise à jour: Je voudrais souligner l'avantage aux extensions d'association par opposition aux méthodes de classe ou champs d'application est que vous avez accès aux composants internes de l'association proxy:

  

proxy_association.owner renvoie l'objet que l'association est une partie de.   proxy_association.reflection renvoie l'objet de réflexion qui décrit l'association.   proxy_association.target renvoie l'objet associé pour belongs_to ou has_one, ou la collection d'objets associés pour has_many ou has_and_belongs_to_many.

Plus de détails ici: http://guides.rubyonrails.org/association_basics.html# association-extensions

Au lieu de champs que je viens de définir des méthodes de classe, qui a travaillé grand

def self.age0 do
  where("blah")
end

J'utilise quelque chose comme:

class Invoice < ActiveRecord::Base
  scope :aged_0,  lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) }
end 

Vous pouvez utiliser fusion méthode afin de fusionner les étendues de modèles différents. Pour plus de détails recherche pour la fusion dans cette Railscast

Si vous essayez juste d'obtenir les commandes de l'utilisateur, pourquoi ne pas simplement utiliser la relation?

Présumant que l'utilisateur actuel est accessible à partir de la méthode current_user dans votre contrôleur:

@my_orders = current_user.orders

Ceci assure ne seront montrées que les commandes spécifiques d'un utilisateur. Vous pouvez également faire emboîtés arbitrairement rejoint obtenir des ressources plus profondes en utilisant joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top