When I try to show linked data in index action - I can't avoid N+1 problem using standart includes. Example:
Model 1 - Pet (let it will be animal: title:string. Pet can has many PetAttributeElems, they show attributes this Pet have and what values they have)
Model 2 - PetAttribute (this model contains only titles of attributes, like weight, age and 1000+ more attributes. PetAttribute has many PetAttributeElems - one attribute, such as weight, can be described for many Pets)
Model 3 - PetAttributeElem (this model belongs to pet and to petAttribute, also it has value field, that show value of attribute for pet.
When I make show
action - I use in HAML:
-@pet.pet_attribute_elems.includes(:pet_attribute).each do |elem|
="#{elem.pet_attribtute.title}: #{elem.value}"
But when I make index
action I want to use:
-@pets.each do |pet|
-pet.pet_attribute_elems.includes(:pet_attribute).each do |elem|
="#{elem.pet_attribtute.title}: #{elem.value}"
That includes
method will call many SQL queries, for every pet
Now I solve it by manually creating additional object like this:
@pet_elems = {}
PetAtributeElems.includes(:pet_attribute)
.where(pet_id:@pets.map(&:id)).each do |elem|
pet_id = elem.pet_id
if @pet_elems.include?(pet_id)
@pet_elems[pet_id] << elem
else
@pet_elems[pet_id] = [elem]
end
end
Than I can use:
-@pets.each do |pet|
-if @pet_elems.include?(pet.id)
-@pet_elems[pet.id].each do |elem|
="#{elem.pet_attribtute.title}: #{elem.value}"
How could I solve that task more easy?