Adam Bronfin
Adam Bronfin

Reputation: 1269

ActiveRecord joins on two models with will_paginate not working to get unique many-to-many relations?

In my Rails 4 application I have a many-to-many relationship between Blogs and Categories with a has_many :through => join table.

I'm using the gem will_paginate to paginate pages of blog posts.

However for each page, I'd like to show the unique categories that are related to every single blog post being shown per page. Currently I have a query like:

Category.joins(:blogs).paginate(page: params[:page], per_page: 20).uniq

This works great for the first page, yet for the second when params[:page] == 2, the result is an empty set of categories even though this second page contains blog posts with categories.

How can I fix this?

EDIT:

action:

  def home
    @categories = Category.joins(:blogs).paginate(page: params[:page], per_page: 20).uniq
    @blogs = Blog.paginate(page: params[:page], per_page: 20)
    respond_to do |format|
      format.html
    end
  end

partial to display categories:

<ul class="filter">
        <li><a class="active" href="" data-filter="*">All</a></li>
        <% @categories.each do |category| %>
            <li><a href="#" data-filter=".<%= category.title.downcase unless nil %>"><%= category.title unless nil  %></a></li>
        <% end %>
 </ul>

The partial logic is less relevant here compared to the collection of blogs and categories being populated in the action.

Upvotes: 0

Views: 1633

Answers (2)

troelskn
troelskn

Reputation: 117427

If your database supports it, one option is to use a subquery. So:

Category
  .all
  .select("categories.*, (select count(blogs.id) from blogs where blogs.category_id = categories.id) as number_of_blogs")
  .paginate(page: params[:page], per_page: 20)

Upvotes: 0

Alejandro Babio
Alejandro Babio

Reputation: 5229

If I understand the question: You are trying to show the blogs with its categories without duplication.

Then you can do this way:

blogs = Blog.includes(:categories).paginate(page: params[:page], per_page: 20)

There no reason for show a category more than 1 time, unless you duplicated the relation, but you must prevent that.

If you do:

 @categories = Category.joins(:blogs).paginate(page: params[:page], per_page: 20)

you got up to 20 records of categories. Each of them, with all its blogs.

You must not do this: @blogs = Blog.paginate(page: params[:page], per_page: 20), because you can't paginate with the same params[:page] as @categories, and you have the blogs data attached to each category.

With only the @categoríes setted you can do at your view:

<% @categories.each do |category| %>
  <%= "#{category.name} has #{category.blogs.size} blogs" %>
  <% category.blogs.each do |blog|>
    <%= blog.author %>
  <% end %>
<% end %>

And you don't need the instance variable @blogs at all.

EDIT: Answer revealed through private chat:

categories = []
blogs.each do |b|
   categories.push(*b.categories)
end
categories.uniq

Upvotes: 1

Related Questions