Quel est l’équivalent de l’option has_many ‘conditions’ dans Rails 4?

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
  • dans le processus passé à :conditions , self n’est pas toujours une instance de modèle (par exemple lorsque l’association est fusionnée avec une autre requête)
  • L’utilisation de SQL brut au sein de vos étendues et associations entraînera probablement des problèmes à un moment ou à un autre avec la mise en place des noms de tables … utilisez AREL.

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