rodsoars
rodsoars

Reputation: 401

Two has_many associations to the same model

I have a blog model that has many posts and some of these posts are top posts. My intention is to have something like the following.

class Blog
  has_many :posts
  has_many :top_posts, class_name: 'Post'
end

class Post
  belongs_to :blog
end

As you can see, posts and top posts are the same objects, but the collection of top posts is different from the collection of posts. Some posts are top posts too, but others not.

The problem is when I try to do blog.top_posts, it returns the same collection as blog.posts, which are all posts from that blog. I want blog.top_posts to return only the posts I have associated as the blog's top posts via blog.top_post_ids << random_post. Thanks in advance!

Upvotes: 0

Views: 371

Answers (3)

Tanguy S
Tanguy S

Reputation: 133

I will assume that , like David asked you in comment , you have particular post.

And a post could become a top_post if , by example , he has 50 likes , or 1000 views , or wathever attributes persistent in your database making a post become a top post .

If you don't have any criteria persistent on your database , you can't use active record to gets top_post. Anyway if you have , you should use a scope :

 class Blog
  has_many :posts

 end

class Post
  belongs_to :blog
  scope :top_posts, -> { where(views > 1000 ) }  #or any conditions base on your criterias
end

And you can get them simply :

    blog = Blog.first
    blog.posts.top_posts # => [top posts belonging to this blog]

it's an answer based on assumption ...

doc for scope : http://guides.rubyonrails.org/active_record_querying.html#scopes s

Upvotes: 1

Mathijs
Mathijs

Reputation: 66

How about a scope? http://guides.rubyonrails.org/active_record_querying.html#scopes

    class Blog
      has_many :posts
    end

    class Post
      belongs_to :blog
      scope :top, -> { where top_post: true }
    end

    # this gets all the top posts
    blog.posts.top

Upvotes: 1

MCBama
MCBama

Reputation: 1480

The problem with using the has_many is it simply attaches the ID of your Blog object to each Post object so when you call blog.posts or blog.top_posts it executes a SQL query looking for Posts WITH id=Blog.id thus, you get the same list twice.

I would suggest you have a single has_many posts and then sort the list that is returned by whatever makes each post the "Top Post." Or, if you'd like to avoid sorting I'd suggest something like this:

class Blog
  has_many :posts

  def initialize
    @top_posts = []
  end

  def add_top_post(post)
    if self.posts.include?(post)
      @top_posts << post
    end
  end
end

class Post
  belongs_to :blog
end

Upvotes: 1

Related Questions