Je me demandais si les gens pouvaient partager leur approche préférée pour filtrer le contenu d'une relation has_many par une autre clé étrangère. Par exemple, supposons que vous ayez trois entités: Départements, Employés, Projets. Un département a beaucoup d'employés, et un projet a beaucoup d'employés. J'ai un projet, et je veux obtenir tous ses employés d'un département donné. Mon code ressemble à ceci:Rails: Filtre relation has_many par une autre clé étrangère
# department.rb
has_many :employees
# employee.rb
belongs_to :department
belongs_to :projects
# project.rb
has_many :employees
Maintenant, je peux penser à quatre approches à mon problème:
APPROCHE 1: méthodes d'interrogation de classe:
# anywhere.rb
Employee.where(:project_id => project, :department_id => department)
APPROCHE 2: Méthode d'assistance
# project.rb
def employees_from_department(department)
employees.select { |emp| emp.department == department }
end
APPROCHE 3: méthode d'assistance sur la relation
# project.rb
has_many :employees do
def from_department(department)
where(:department_id => department)
# Could also be all.select { |emp| emp.department == deparment }
end
end
APPROCHE 4: Scopes
# employee.rb
scope :from_department, lambda { |department|
where(:department_id => department)
}
# anywhere.rb
project.employees.from_department(department)
Je choisis presque toujours l'approche # 4, car il est le plus réutilisable. Je peux appliquer cette portée à n'importe quelle requête qui renvoie Employees. Je peux combiner avec d'autres champs d'application, définir une commande, etc. Plus à l'aide des étendues signifie toute ma lecture seule, le code de style de requête est nommé assez cohérente et organisée en haut, donc j'avoir moins de méthodes. Les portées sont l'une de mes fonctionnalités Rails préférées. Mais je me trouve en train de les écrire/tout le temps /, de sorte que j'ai presque une portée paramétrée pour correspondre à chaque: belongs_to. Est-ce la bonne approche? En outre, il semble que je générer une tonne de requêtes de base de données, alors je me demande si je suis battu des Rails de mise en cache aurait pu faire pour moi, parce que mon champ est contraint Rails pour aller à la base de données à chaque fois.
Ceci est en partie une question de performance, ce qui signifie qu'il n'y a pas une taille unique toute réponse, et vous avez besoin de tester le code dans la production de trouver la bonne façon. Mais avant que votre code ne soit en production, quelle approche avez-vous tendance à choisir? Ou s'agit-il d'autre chose?
# 1, # 3 devrait générer le même SQL (sauf si vous utilisez 'all.select' dans # 3). Quant à # 4, où est le 'projet'? N'utilisez pas # 2, il récupérera des données excessives, 'employees.find (: all,: conditions => ...)' ou '.find_by _...' ou probablement 'where' sont beaucoup mieux dans ce cas. –
@Victor: J'ai modifié le code pour # 4 pour montrer comment la portée est utilisée. –