Home > Software engineering >  How do I iterate through a has_many :through association in ERB without producing duplicates?
How do I iterate through a has_many :through association in ERB without producing duplicates?

Time:11-30

I'm new to Rails and I am creating a fairly simple site in Rails that has three models: Section, Category, and Post. A Section and a Category both have many posts, so logically I used Post as a join model, and from most of my testing this seems to work. So, my models are as follows:

class Category < ApplicationRecord
   has_many :posts
   has_many :sections, through: :posts
end

class Post < ApplicationRecord
   belongs_to :section
   belongs_to :category
end

class Section < ApplicationRecord
   has_many :posts
   has_many :categories, through: :posts
   
   has_rich_text :description

   def to_param
      url
   end
end

I've seeded the database with the following:

general = Section.create(title: "General", description: "Description of the General section", url: "general")
c1 = Category.create(title: "Cat1", description: "Desc1")
p1 = Post.create(title: "Post 1", blurb: "Blurb 1", body: "Body 1", section: general, category: c1)
p2 = Post.create(title: "Post 2", blurb: "Blurb 2", body: "Body 2", section: general, category: c1)

My main issue I'm having right now is taking advantage of the associations in the Show page of the current Section in ERB. If I have more than one Post, it outputs the first iterator over and over again until it runs out of Posts. Here's my ERB:

<% @section.each do |s| %>
  <% if request.path == section_path(s) %>
    <% s.categories.each do |c| %>
      <h1><%= c.title %></h1>
      <p><%= c.description %></p>
      <% c.posts.each do |p| %>
        <%= p.title %>
      <% end %>
    <% end %>
  <% end %>
<% end %>

So, in this example, it had two posts. So it printed everything out twice. Here's the resulting HTML:

      <h1>Cat1</h1>
      <p>Desc1</p>
        Post 1
        Post 2
      <h1>Cat1</h1>
      <p>Desc1</p>
        Post 1
        Post 2

I'm thinking about going into the controller and doing the iterations in a hash table, and the passing the hash to the view to go over. However, I don't feel that this will scale and the more content I have eventually the slower that will become, affecting load times, etc. I also don't feel it's idiomatic as far as Rails goes, and there has to be a cleaner way. Can anyone show me what I'm doing wrong here? Thanks in advance for any suggestions/help :)

Edit 1: The expected HTML output is just

     <h1>Cat1</h1>
      <p>Desc1</p>
        Post 1
        Post 2

not the way its repeated twice above. It repeats everything proportional to number of poats for some reason, so if there was a Post 3, it would display everything 3 times. I want everything to display exactly once.

Edit 2: I should probably also mention that in the controller, @section = Section.all

CodePudding user response:

Add uniq or distinct after categories can solve this problem

<% s.categories.uniq.each do |c| %>
  <h1><%= c.title %></h1>
  <p><%= c.description %></p>
  <% c.posts.each do |p| %>
    <%= p.title %>
  <% end %>
<% end %>

What's the difference?

  • uniq is an Array method that removes the repeated record in an array.
  • distinct is an ActiveRecord method that adds an actual DISTINCT in the SQL phrase and it will trigger a database query.

You can choose anyone depending on your situation.

  • Related