David Tuite
David Tuite

Reputation: 22663

Database model for favoriting items.

I have a Rails app with users, suggestions and searches. There is a many-to-many association between users and searches such that each user can be in many searches and each search can have many users (called "searchers").

Users can make suggestions into each Search they are a member of. Thus, each Suggestion belongs to a User and a Search.

class Suggestion < ActiveRecord::Base
  belongs_to :suggester, class_name: 'User'
  belongs_to :search
end

class Search < ActiveRecord::Base
  # ... user-search associations.

  has_many :suggestions
end

class User < ActiveRecord::Base
  # ... user-search associations.

  has_many :suggestions, foreign_key: :suggester_id
end

Now, I'm trying to allow users to favorite suggestions which are made into searches they are a member of. The snag is that user's can favorite suggestions which were made by team mates as well as suggestions which they made themselves. This means that favoriting cannot be accomplished via a simple favorite attribute on Suggestion.

I have tried to make Favorite a join model between User and Suggestion.

class Favorite < ActiveRecord::Base
  belongs_to :user
  belongs_to :suggestion
end

However, I am having trouble accessing the suggestions which have been favorited by a particular user from within a particular search. For example:

class Search < ActiveRecord::Base
  has_many :suggestions

  def suggestions_favoured_by(user)
    # here I need to grab the search's suggestions and then scope them
    # down to only these that have an entry in the favorites table which
    # has user_id == user.id.
    # That seems ridiculously complicated.
  end
end

The only way I can think to solve this problem is to add a search_id attribute to Favorite. However, that would de-normalize my favorites table because a favorite belongs to a suggestion which belongs to a search, and a favorite also belongs to a search directly.

The only other idea that I can think of (and I haven't tried to implement this yet, I'm having trouble visualizing where it's going to lead me in my head) is that the user - favorite association should happen through the join model between User and Search, rather than on the User and Search models seperately (because that would de-normalize the table).

Whats the best way to architect this?

My apologies for the long-winded nature of the question.

Upvotes: 0

Views: 171

Answers (1)

Edward Anderson
Edward Anderson

Reputation: 13926

You can do this with a scope, without implementing a suggestions_favoured_by method that would do the filtering manually.

class Suggestion < ActiveRecord::Base
  has_many :favorites
  scope :favoured_by, lambda { |user_id|
    joins(:favorites).
    where(:favorites => {:user_id => user_id})
  }
end

Then to access a User's favorite suggestions for a particular search:

search.suggestions.favoured_by(user_id)

Rails will take care of building the SQL query, and your associations stay normalized.

Upvotes: 1

Related Questions