2

Here my models:

class User < ActiveRecord::Base
  has_many :bookmarks
end

class Topic < ActiveRecord::Base
  has_many :bookmarks
end

class Bookmark < ActiveRecord::Base
  belongs_to :user
  belongs_to :topic
  attr_accessible :position
  validates_uniqueness_of :user_id, :scope => :topic_id
end

I want to fetch all topics with, for current_user, the associated bookmark. ATM, I do:

Topic.all.each do |t|
    bookmark = t.bookmarks.where(user_id: current_user.id).last
    puts bookmark.position if bookmark
    puts t.name
end

This is ugly and do too much DB queries. I would like something like this:

class Topic < ActiveRecord::Base
  has_one :bookmark, :conditions => lambda {|u| "bookmarks.user_id = #{u.id}"}
end

Topic.includes(:bookmark, current_user).all.each do |t| # this must also includes topics without bookmark
    puts t.bookmark.position if t.bookmark
    puts t.name
end

Is this possible? Have I any alternative?

Thank you!

Habax
  • 1,274
  • 17
  • 26

1 Answers1

6

*Hmm I'm not sure I understood your question but this may help you:

# code
class Topic < ActiveRecord::Base
  scope :for_user, lambda { |user| includes(:bookmarks).where(bookmarks: { user_id: user.try(:id) || user} ) }

# call
Topic.for_user(current_user) # => Array of Topics

As you can see the parameter of the scope for_user can be a User object OR a user id.

Hope this helps!

Similar questions:

Community
  • 1
  • 1
MrYoshiji
  • 54,334
  • 13
  • 124
  • 117
  • 1
    `includes` excludes unbookmarked `topics`. From your idea, I change it into a `joins` : `scope :for_user, lambda { |user| select('topics.*, bookmarks.position as position).joins("LEFT JOIN bookmarks ON bookmarks.topic_id = topics.id AND bookmarks.user_id = #{user.try(:id) || user}") }`. Then in the code : `Topic.for_user(current_user)`. `joins` seems not to select attributes by default. I'm looking for a cleaner solution, but it does the work. Thank you :) – Habax Nov 22 '12 at 17:15