There are posts (table posts). You can add categories to posts - many connection to many.

Now I can display posts of specific categories:

Post.all.where(posts_and_categories: { category_id: [2, 4] }).joins(:posts_and_categories) 

But how can I make it so that I can display posts that have no categories?

    1 answer 1

    Rails 5 is cool!

    Rails 5 introduced the left connections ( LEFT JOIN , it explains what kind of animal it is ), so this is done without any digging under the hood, rail means:

    • take posts
    • left-connect with their permanent categories
    • select posts that instead of the post-category turned out to be NULL s
      • it is enough to check that the post_id value is NULL , since it is an association key, it falls into the predicate of the connection, and NULL not equal to NULL , therefore only the lines for which no post-category was found under the condition
     Post.left_joins(:posts_and_categories) .merge(PostsAndCatrgory.where(post_id: nil)) 

    But in older versions ...

    And earlier I would suggest (and suggested ) using the NOT EXISTS SQL:

     Post.where( "NOT EXISTS (?)", PostsAndCategory.where("posts_and_categories.post_id = post.id") ) 

    ... but you can get rid of the pieces of SQL by taking Arel (the ActiveRecord query designer is already built on it, so you don’t need to install anything else):

     Post.where( PostsAndCategory.where( post_id: Post.arel_table[:id] ) .exists .not ) 

    The second solution looks even more transparent, it says more directly what is being searched for. Is that the speed of work is worth checking. But it does not use data on associations, which is a minus.