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-any
RÉPONSE À LA MISE À JOUR:
Placez la commande à l'intérieur du bloc:
has_many :friends, -> { where(friendship: {status: 'accepted'}).order('first_name DESC') }, :through => :friendships
Bien que d’autres réponses soient techniquement correctes, elles violent l’encapsulation. Le modèle User ne doit pas savoir que le modèle Amitié a une colonne appelée status
et qu'il peut avoir une valeur spécifique telle que accepted
.
Si vous décidez d’apporter une modification, pour tirer parti d’Enums dans Rails 4, par exemple, vous devrez modifier à la fois User et Amitié modèles. Cela pourrait conduire à des bogues évités par le maintien de l'encapsulation.
J'exposerais une portée dans le modèle Amitié:
scope :accepted, -> { where(status: :accepted) }
J'utiliserais ensuite cette portée dans le modèle User, en masquant tous les détails de la mise en œuvre à User.
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 portée en accepted_friendships
être plus clair.
has_many :accepted_friendships, -> { Friendship.accepted }
has_many :friends, through: :accepted_friendships
Vous avez maintenant encapsulé avec succès les détails de la mise en œuvre dans leurs modèles respectifs. Si quelque chose change, vous n’avez qu’un seul endroit pour le changer, ce qui réduit la maintenance et augmente 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
NOTES:
where_ast
est important car il renvoie les nœuds AREL nécessaires au fonctionnement de la condition.: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), je devais 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 base de données.
has_many :friends, -> { where(status: 'accepted').order('frist_name')}, through: :friendships
ou
has_many :friends, -> { where(status: 'accepted').order(:frist_name)}, through: :friendships