0

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?

user2572790
  • 442
  • 3
  • 13
  • [Maybe you're solving the wrong task (semi-related reading)...](https://stackoverflow.com/questions/26247288/reducing-n1-queries-using-the-bullet-and-rspec-gems/26251892#26251892) – Brad Werth Mar 01 '17 at 23:18
  • I hope you are right) but now I need to show in Index action linked data without N+1 queries – user2572790 Mar 01 '17 at 23:25

1 Answers1

1

You're going down a non rails-convention path.

Move code out of the views so it's simply

= render @pet_attribute_elems

Make a partial to handle display

# _pet_attribute_elems.html.haml
="#{pet_attribute_elem.pet_attribtute.title}: #{pet_attribute_elem.value}"

In the controller, do the queries

def show

  @pet = Pet.find(...)
  @pet_attribute_elems = @pet.pet_attribute_elems.includes(:pet_attribute)

end

def index

  @pet_attribute_elems = PetAttributeElem.includes(:pet_attribute)

end
Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70