Home > Software design >  How to access has_many through relationship possible in rails?
How to access has_many through relationship possible in rails?

Time:02-10

How can I access my related records?

class Post < ActiveRecord::Base
has_many :post_categories
has_many :categories, through: :post_categories

class Categories < ActiveRecord::Base
has_many :post_categories
has_many :post, through: :post_categories

class PostCategories < ActiveRecord::Base
belongs_to :post
belongs_to :category

PostCategories table has id, posts_id, and categories_id columns.

id | posts_id | categories_id
1. | 2       | 3
2. | 2       | 4

What I want is: to get posts related to a category. like: all Posts where in x category.

CodePudding user response:

Yep, this is an easy one.

one_or_more_categories = # Category.find... or Category.where...
posts = Post.joins(:categories).where(category: one_or_more_categories)

Rails is clever enough to take either a model or a query that would find some data and turn that into an efficient appropriate query, that might be a subquery. Trying things out in the Rails console (bundle exec rails c) is a good way to see the generated SQL and better understand what's going on.

(EDIT: As another answer points out, if you've already retrieved a specific Category instance then you can just reference category.posts and work with that relationship directly, including chaining in .order, .limit and so-on).

Another way to write it 'lower level' would be:

Post.joins(:categories).where(category: {id: one_or_more_category_ids})

...which is in essence what Rails will be doing under the hood when given an ActiveRecord model instance or an ActiveRecord::Relation. If you already knew the e.g. category "name", or some other indexed text column that you could search on, then you'd adjust the above accordingly:

Post.joins(:categories).where(category: {name: name_of_category})

The pattern of joins and where taking a Hash where the join table name is used as a key with values nested under there can be taken as deep as you like (e.g. if categories had-many subcategories) and you can find more about that in Rails Guides or appropriate web searches. The only gotcha is the tortuous singular/plural stuff, which Rails uses to try and make things more "English-y" but sometimes - as in this case - just creates an additional cognitive burden of needing to remember which parts should be singular and which plural.

CodePudding user response:

Not sure if this answers it but in ActiveRecord your Post will have direct access to your Category model and vice versa. So you could identify the category you want the posts from in a variable or an instance variable, and query @specific_category.posts. If you are doing this in your controller, you could even do it in before_action filter. If you are using it in serializers its not much different.

You could also create a scope in your Post model and use either active record or raw SQL to query specific parameters.

You also have an error in your Category model. Has many is always plural so it would be has_many :posts, through: :post_categories

CodePudding user response:

Get the category object and you can directly fetch the related posts. Please see the following

category = Category.find(id)
posts = category.posts

Since you have already configured the has_many_through relation, rails will fetch post records related the category.

  • Related