59 votes

Comment portez-vous les associations ActiveRecord dans Rails 3?

J'ai un Rails 3, du projet. Avec Rails 3 est venu Arel et la possibilité de réutiliser un champ d'application à construire une autre. Je me demande si il existe un moyen d'utiliser des étendues lors de la définition d'une relation (par exemple, un "has_many").

J'ai des dossiers qui ont l'autorisation de colonnes. Je voudrais construire un default_scope qui prend ma permission colonnes en considération, de sorte que les enregistrements (y compris ceux accessibles via un lien) sont filtrés.

Actuellement, dans Rails 3, default_scope (y compris les patchs que j'ai trouvé) ne donnent pas une pratique les moyens de passer à un proc (dont j'ai besoin pour la fin de l'variable de liaison). Est-il possible de définir un has_many dans laquelle un nom de champ peut être adoptée?

L'idée de la réutilisation d'une étendue nommée ressemblerait à:

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

Ou implicitement de codage, le nom de champ dans la relation ressemblerait à:

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

J'essaye simplement d'appliquer default_scope avec la liaison tardive. Je préfère utiliser un Arel approche (si il y en a un), mais l'utilisation de toute option viable.

Depuis que je suis en se référant à l'utilisateur actuel, je ne peux pas compter sur des conditions qui ne sont pas évalués au dernier moment possible, tels que:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]

21voto

Franck Verrot Points 786

Je vous suggère de prendre un coup d'oeil à "Nommé étendues sont morts"

L'auteur explique comment puissant Arel est :)

J'espère que ça vous aidera.

EDIT #1 Mars 2014

Comme certains commentaires l'état, à la différence maintenant est une question de goût personnel.

Cependant, je recommande personnellement pour éviter d'exposer Arel du champ d'application d'une couche supérieure (un contrôleur ou quoi que ce soit d'autre que l'accès aux modèles directement), ce qui nécessite:

  1. Créer un champ d'application, et de l'exposer à travers une méthode dans votre modèle. Cette méthode permettrait de vous exposer au contrôleur;
  2. Si vous n'exposez jamais vos modèles pour vos contrôleurs (si vous avez une sorte de couche de service), alors vous êtes beaux. L'anti-corruption de la couche est à votre service et il peut accéder à votre modèle est portée sans trop se préoccuper de la façon dont les étendues sont mis en œuvre.

20voto

Peter P. Points 973

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)
 

15voto

Kevin Points 1618

Au lieu de portées j’ai juste été définissant méthodes de la classe, qui a été génial de travailler

10voto

craig Points 11198

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 
 

9voto

ramigg Points 653

Vous pouvez utiliser la méthode de fusion afin de fusionner les étendues de différents modèles. Pour plus de détails, recherchez Fusionner dans ce Railscast.

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