Quelqu’un peut-il me dire quelle est la manière équivalente de faire la ligne suivante dans Rails 4?
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'", :order => :first_name
J’ai essayé ce qui suit:
has_many :friends, -> { where status: 'accepted' }, :through => :friendships , :order => :first_name
Mais j’obtiens l’erreur suivante:
Invalid mix of scope block and deprecated finder options on ActiveRecord association: User.has_many :friends
Doit être le deuxième argument:
class Customer < ActiveRecord::Base has_many :orders, -> { where processed: true } end
http://edgeguides.rubyonrails.org/association_basics.html#scopes-for-has-many
RÉPONSE À LA MISE À JOUR:
Mettez la commande dans le bloc:
has_many :friends, -> { where(friendship: {status: 'accepted'}).order('first_name DESC') }, :through => :friendships
Bien que d’autres réponses soient techniquement correctes, elles enfreignent l’encapsulation. Le modèle User ne doit pas savoir que le modèle Friendship a une colonne appelée status
et qu’il peut avoir une valeur spécifique, telle accepted
.
Si vous décidez de faire un changement, par exemple pour tirer parti de Enums in Rails 4, vous devrez modifier les modèles User et Friendship . Cela pourrait conduire à des bogues que le maintien de l’encapsulation évite.
Je voudrais exposer une scope dans le modèle de l’ amitié :
scope :accepted, -> { where(status: :accepted) }
J’utiliserais alors cette scope dans le modèle utilisateur , en masquant les détails d’implémentation de l’ utilisateur .
has_many :friendships, -> { Friendship.accepted } has_many :friends, through: :friendships # Or... has_many :friends, -> { Friendship.accepted }, through: :friendships
Vous pouvez aller plus loin et renommer la scope sur accepted_friendships
pour la rendre plus claire.
has_many :accepted_friendships, -> { Friendship.accepted } has_many :friends, through: :accepted_friendships
Vous avez maintenant encapsulé avec succès les détails d’implémentation dans leurs modèles respectifs. Si quelque chose devait changer, vous n’avez qu’un seul endroit pour le changer, en réduisant la maintenance et en augmentant la robustesse.
Une version de Rails 3.2 de la réponse de Mohamad serait la suivante:
class Friend < ActiveRecord::Base has_many :friendships, :order => :first_name has_many :friends, :through => :friendships, :conditions => proc { Friendship.accepted.where_ast } has_many :pending_friends, :through => :friendships, class_name => Friend, :conditions => proc { Friendship.pending.where_ast } end class Friendship < ActiveRecord::Base scope :status, ->(status) { where(:status => status) } scope :accepted, -> { status('accepted') } scope :pending, -> { where(arel_table[:status].not_eq('accepted')) } end
REMARQUES:
where_ast
est important car il retourne les nœuds AREL requirejs pour que la condition fonctionne :conditions
, self
n’est pas toujours une instance de modèle (par exemple lorsque l’association est fusionnée avec une autre requête) Pour travailler sur Rails 4.1 (mon cas), j’ai dû mettre:
has_many :friends, -> { where(friendships: { status: 'accepted' }) }, through: :friendships
Notez le S sur les amitiés. Il fait directement référence au nom de la firebase database.
has_many :friends, -> { where(status: 'accepted').order('frist_name')}, through: :friendships
ou
has_many :friends, -> { where(status: 'accepted').order(:frist_name)}, through: :friendships