Iterating using css grid
Hi Chris - I am using CSS grid for a three-column blog layout. Unfortunately, when I run the do bock it creates three instances of the same post. I guess this is to be expected.
Not sure how to get around this issue with CSS grid. Wondering if you might know of a fix?
I put a basic example below.
.someclass {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
}
Index page
<% @posts.each do |post| %>
# grid one
<div class="grid-1">
<%= post.title %>
</div>
# grid two
<div class="grid-2">
<%= post.title %>
</div>
# grid three
<div class="grid-3">
<%= post.title %>
</div>
<% end %>
Yep, makes sense. You need to slice the array into groups of 3, then loop through each one of those instead.
<% @posts.each_slice(3) do |posts| %>
<% posts.each_with_index do |post, index| %>
<div class="grid-<%= index + 1%>">
<%= post.title %>
</div>
<% end %>
<% end %>
And actually, if I were using TailwindCSS for CSS grid, I would do the following and set the grid to 3 columns.
<div class="grid grid-cols-3">
<% posts.each_with_index do |post, index| %>
<div>
<%= post.title %>
</div>
<% end %>
</div>
Awesome you saved me! It probably would have taken me a week to figure that out. Thank you.
I wanted to rebuild a site without using a CSS framework. But I will try out Tailwind on my next project.
Tailwind isn't your typical framework. It's just classes that wrap like one line of CSS so you'll end up learning CSS really quickly and better this way I've noticed. That's how I taught myself grid in the last month actually.
Hey Chris - Just a follow up on this question. I am seeing a bunch of duplicate entries: https://gympass.ca/fitness-facilities for some reason?
<div class="clubs__index">
<% @gyms.each_slice(3) do |gyms| %>
<% @gyms.each_with_index do |gym, index| %>
<div class="clubs__index--<%= index + 1 %>">
<%#= render 'gyms/card' %>
<div class="card">
<% if gym.image.present? %>
<%= image_tag gym.image.url, class: 'card__image', alt: gym.gym_name, size: "700X500" %>
<% else %>
<%= image_tag 'https://ficdn-files.ca/images/gympass/logo/default_club_image_index.jpg', class: 'card__image', loading: "lazy" %>
<% end %>
<h3 class="card__title"><%= gym.gym_name %></h3>
<h5 class="card__address">
<%= gym.gym_address.titleize %><br>
<%= gym.gym_city.titleize %> / <%= gym.province.name if gym.province %><br>
<%= gym.gym_postal.insert(3, ' ').upcase %>
</h5>
<p class="card__details">
<span class="card__details--bold"><%= t("gyms_index.telephone") %></span>
<%= number_to_phone(gym.gym_telephone, area_code: true ) %><br>
<% if gym.ext.present? %>
<span class="card__details--bold"><%= t("gyms_index.ext") %></span>
<%= gym.ext %><br>
<% end %>
<% if gym.gym_email.present? %>
<span class="card__details--bold"><%= t("gyms_index.email") %></span>
<%= gym.gym_email.downcase %>
<% end %>
</p>
<p class="card__url">
<% if gym.gym_website.present? %>
<%= link_to url_for(gym.gym_website), target: '_blank' do %>
<%= truncate(gym.gym_website.downcase.try(:remove, /.*\/\//), :escape => false, :length => 44) %>
<% end %>
<% end %>
</p>
<ul class="card__social">
<% if gym.gym_facebook.present? %>
<li class="card__social--items">
<%= link_to gym.gym_facebook, target: '_blank' do %>
<i class="card__social--icons fab fa-facebook-f"></i>
<% end %>
</li>
<% end %>
<% if gym.gym_twitter.present? %>
<li class="card__social--items">
<%= link_to gym.gym_twitter , target: '_blank' do %>
<i class="card__social--icons fab fa-twitter"></i>
<% end %>
</li>
<% end %>
<% if gym.gym_instagram.present? %>
<li class="card__social--items">
<%= link_to gym.gym_instagram, target: '_blank' do %>
<i class="card__social--icons fab fa-instagram"></i>
<% end %>
</li>
<% end %>
<% if gym.gym_youtube.present? %>
<li class="card__social--items">
<%= link_to gym.gym_youtube, target: '_blank' do %>
<i class="card__social--icons fab fa-youtube"></i>
<% end %>
</li>
<% end %>
</ul>
<% if logged_in? %>
<ul class="card__admin">
<li class="card__admin--items">
<%= link_to 'View', gym, class: "link-padding" %>
</li>
<li class="card__admin--items">
<%= link_to 'Edit', edit_gym_path(gym), class: "link-padding" %>
</li>
<li class="card__admin--items">
<%= link_to 'Destroy', gym, method: :delete, data: { confirm: 'Are you sure?' }, class: "link-padding" %>
</li>
</ul>
<% end %>
</div> <%# card %>
</div>
<% end %> <%# do block end %>
<% end %>
</div> <%# clubs index %>
it's not stopping at 3 when it counts, eg
def index
@q = Gym.ransack(params[:q])
@gyms = @q.result.includes(:province).page(params[:page]).order("created_at DESC").paginate(:page => params[:page], :per_page => 18)
end
You've got 18 per page in your pagination. Then you're not using the slice you defined.
<% @gyms.each_slice(3) do |gyms| %>
<% @gyms.each_with_index do |gym, index| %>
You see the second line where you're using @gyms
a second time? That should be gyms
You're accidentally looping through each group of 3, then rendering all 18 for each of those groups. 😜
One thing that can help is extracting out things into partials, that way you can see your code a bit clearer. Looks like you were on that path, but it's commented out. I try and do that from the very beginning and that makes sure I have my loops setup correctly.
I had it originally in a partial, but it was throwing an error for undefined local variable or method for gym.
<% if gym.image.present? %>
Yeah, you want to pass it in as a local variable like so:
<%= render 'gyms/card', locals: { gym: gym, index: index } %>
Partials need locals passed in so it can assign those variables and use them the same way as the parent template was.
I had to add partial and it worked. Cheers,
<%= render partial: 'card', locals: { gym: gym, index: index } %>