In my Rails 6 app I have these models:
class User < ApplicationRecord
has_many :read_news_items
has_many :news_items, :through => :read_news_items
end
class NewsItem < ApplicationRecord
has_many :read_news_items
has_many :users, :through => :read_news_items
def read?(user)
read_news_items.where(:user_id => user.id).any?
end
end
class ReadNewsItem < ApplicationRecord
belongs_to :user
belongs_to :news_item
end
In my controller action I want to list all news items and highlight the ones that have not yet been read by the user:
class NewsItemsController < ApplicationController
def index
@news_items = NewsItem.all
end
end
The problem is that this generates N 1 queries for each record because the read?(current_user)
gets called for each user
record.
How can this problem be overcome?
I tried appending includes(:read_news_items)
and joins(:read_news_items)
to the database query in my controller but to no avail.
CodePudding user response:
You could try:
class NewsItem < ApplicationRecord
has_many :read_news_items
def read?(user)
if read_news_items.loaded?
read_news_items.any? {|rni| rni.user_id == user.id }
else
read_news_items.where(:user_id => user.id).any?
end
end
end
class NewsItemsController < ApplicationController
def index
@news_items = NewsItem.includes(:read_news_items).all
end
end
CodePudding user response:
OK, I learned something from every answer that was given here. So thanks for that.
I changed my read?
method to the following which seems to have eliminated the N 1 queries:
class NewsItem < ApplicationRecord
def read?(user)
(user.read_news_items.pluck(:news_item_id)).include?(id)
end
end