Page companies by category Rails

3

I am trying to paginate the companies by categories, with the idea that I have a similar view structure:

----------------------------
Categoria: Panaderia
----------------------------
Empresa: Panaderia X
Empresa: Panaderia Y
Empresa: Panaderia Z

Pagina 1,2,3

----------------------------
Categoria: Ferreteria
----------------------------
Empresa: Ferreteria X
Empresa: Ferreteria Y
Empresa: Ferreteria Z

Pagina 1,2,3

----------------------------
Categoria: Hoteles
----------------------------
Empresa: Hoteles X
Empresa: Hoteles Y
Empresa: Hoteles Z

Pagina 1,2,3

This I can achieve without any problem ordering them by group_by in the following way:

enterprises_controller.rb

@enterprises = Enterprise.all.group_by { |e| e.enterprise_tag }

index.html.erb

<% @enterprises.each do |enterprise_tag, enterprises| %>
   <%= enterprise_tag %>
   <% enterprises.each do |enterprise| %>
      <%= enterprise.name %>
   <% end %>
<% end %>

<%= will_paginate @enterprises, :container => false %>

The problem comes when I try to add the pager like this:

@enterprises = Enterprise.all.paginate(:page => params[:page], :per_page => 6).group_by { |e| e.enterprise_tag }

I get the following error:

undefined method 'total_pages' for #<Hash:0x007f7450797d10>
Extracted source (around line #73):

73 <%= will_paginate @enterprises, :container => false %>

I have tried several ways but I can not find the result, could someone give me a suggestion?

    
asked by Hector Hernandez 09.03.2017 в 19:13
source

1 answer

1

The problem is that group_by is not returning a relationship of ActiveRecords but a hash. As far as I've seen in the documentation of the gem will_paginate it does not accept hashes. I think Keminari is a bit more flexible but I have not used it.

One possible solution is to group the results in the views. For this we have to make sure to sort the results by the column with which we want to group. In your case enterprise_tag

#enterprises_controller.rb
def index
  # Devuelve una relación de ActiveRecord con la que puede trabajar will_paginate
  @enterprises = Enterprise.order(enterprise_tag: :asc).paginate(:page => params[:page], :per_page => 6)
end

#index.html.erb
...
<% enterprise_tag = nil %>
<% @enterprises.each do |enterprise| %>
  <% unless enterprise_tag == enterprise.enterprise_tag
    <h3><%= enterprise.enterprise_tag %></h3>
    <% enterprise_tag = enterprise.enterprise_tag %>
  <% end %>
  <h4><%= enterprise.name %></h4>
<% end %>

<%= will_paginate @enterprises %>

As you see in the view, we create and use a variable enterprise_tag to find out if it is the first entry with that tag and in that case put it as the title.

Edit: enterprise_tag is a related table

In this case it is much easier. We do not list the companies but the categories and within each one we make a loop with the companies in that category.

#app/models/enterprise.rb
class Enterprise < ActiveRecord::Base
  ...
  belongs_to :enterprise_tag
  ...
end

#app/models/enterprise_tag.rb
class EnterpriseTag < ActiveRecord::Base
  ...
  has_many :enterprises
  ...
end

#app/controllers/enterprises_controller.rb
def index
  # Devuelve una relación de ActiveRecord con la que puede trabajar will_paginate
  @categorias = EnterpriseTag.includes(:enterprises).paginate(:page => params[:page], :per_page => 6)
end

#index.html.erb
...
<% @categorias.each do |categoria| %>
  <h3><%= categoria.nombre %></h3>
  <% categoria.enterprises.each do |enterprise| %>
    <h4><%= enterprise.nombre %></h4>
  <% end %>
<% end %>
<%= will_paginate @categorias %>

Notes:

  • I do not know what the column with the name is called in either of the two models so I put name . Replace with what corresponds.
  • I include the * .includes (: enterprises) to avoid a new call to the database for each category (N + 1).
answered by 10.03.2017 / 00:45
source