Trenton Tyler
Trenton Tyler

Reputation: 1712

Rails multiple joins into one method

I have a user in my application that can have multiple assessments, plans, and materials. There is already a relationship between these in my database. I would like to show all these in a single tab without querying the database too many times.

I tried to do a method that joins them all in a single table but was unsuccessful. The return was the following error: undefined method 'joins' for #<User:0x007fcec9e91368>

def library
  self.joins(:materials, :assessments, :plans)
end

My end goal is to just itterate over all objects returned from the join so they can be displayed rather than having three different variables that need to be queried slowing down my load times. Any idea how this is possible?

class User < ApplicationRecord
  has_many :materials, dependent: :destroy
  has_many :plans, dependent: :destroy
  has_many :assessments, dependent: :destroy
end 

class Material < ApplicationRecord
  belongs_to :user
end

class Assessment < ApplicationRecord
  belongs_to :user
end

class Plan < ApplicationRecord
  belongs_to :user
end

Upvotes: 0

Views: 40

Answers (2)

Mate Solymosi
Mate Solymosi

Reputation: 5967

If all you want to do is preload associations, use includes:

class User < ApplicationRecord
  # ...

  scope :with_library, -> { includes(:materials, :assessments, :plans) }
end

Use it like this:

User.with_library.find(1)
User.where(:name => "Trenton").with_library
User.all.with_library
# etc.

Once the associations are preloaded, you could use this for your library method to populate a single array with all the materials, assessments and plans of a particular user:

class User < ApplicationRecord
  # ...

  def library
    [materials, assessments, plans].map(&:to_a).flatten(1)
  end
end

Example use case:

users = User.all.with_library
users.first.library
# => [ ... ]

More info: https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

Upvotes: 2

matthewd
matthewd

Reputation: 4420

Prefer includes over joins unless you have a specific reason to do otherwise. includes will eliminate N+1 queries, while still constructing usable records in the associations: you can then loop through everything just as you would otherwise.

However, in this case, it sounds like you're working from a single User instance: in that case, includes (or joins) can't really help -- there are no N+1 queries to eliminate.

While it's important to avoid running queries per row you're displaying (N+1), the difference between one query and three is negligible. (It'd cost more in overhead to try to squish everything together.) For this usage, it's just unnecessary.

Upvotes: 0

Related Questions