J’ai un projet Rails 3. Avec Rails 3 est venu Arel et la possibilité de réutiliser un domaine pour en construire un autre. Je me demande s’il existe un moyen d’utiliser les étendues lors de la définition d’une relation (par exemple, un “has_many”).
J’ai des enregistrements qui ont des colonnes d’autorisation. Je voudrais construire un default_scope qui prenne en compte mes colonnes de permission afin que les enregistrements (même ceux accessibles via une relation) soient filtrés.
Actuellement, dans Rails 3, default_scope (y compris les correctifs que j’ai trouvés) ne fournit pas un moyen pratique de passer un proc (dont j’ai besoin pour la liaison des variables tardives). Est-il possible de définir un has_many dans lequel une scope nommée peut être transmise?
L’idée de réutiliser une étendue nommée ressemblerait à ceci:
Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)} has_many :orders, :scope => Orders.my_orders
Ou, implicitement, le codage de l’étendue nommée dans la relation ressemblerait à ceci:
has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}
J’essaie simplement d’appliquer default_scope avec une liaison tardive. Je préférerais utiliser une approche Arel (s’il y en a une), mais utiliserais n’importe quelle option réalisable.
Comme je fais référence à l’utilisateur actuel, je ne peux pas compter sur des conditions qui ne sont pas évaluées au dernier moment, par exemple:
has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
Je vous suggère de jeter un coup d’oeil à “Les scopes nommées sont mortes”
L’auteur explique comment Arel est puissant 🙂
J’espère que ça va aider.
Comme l’indiquent certains commentaires, la différence est maintenant une question de goût personnel.
Cependant, je recommande toujours d’éviter d’exposer le domaine d’Arel à un niveau supérieur (en tant que contrôleur ou autre élément qui accède directement aux modèles), ce qui nécessiterait:
Qu’en est-il 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: J'aimerais souligner l'avantage des extensions d'association par rapport aux méthodes ou aux étendues de classe: vous avez access aux éléments internes du proxy d'association:
proxy_association.owner renvoie l'object dont l'association fait partie. proxy_association.reflection renvoie l'object de reflection qui décrit l'association. proxy_association.target retourne l'object associé pour belongs_to ou has_one, ou la collection d'objects 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 scopes, je viens de définir des méthodes de classe qui fonctionnent très bien
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 la méthode de fusion pour fusionner les étendues de différents modèles. Pour plus de détails chercher pour fusionner dans ce railcast
Si vous essayez seulement d’obtenir les commandes de l’utilisateur, pourquoi ne pas simplement utiliser la relation?
En supposant que l’utilisateur actuel est accessible depuis la méthode current_user de votre contrôleur:
@my_orders = current_user.orders
Cela garantit que seuls les ordres spécifiques d’un utilisateur seront affichés. Vous pouvez également faire des jointures nestedes de manière arbitraire pour obtenir des ressources plus profondes en utilisant des joins
current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)