How to change code of every nth iteration - ruby-on-rails

I got the following code in an .erb document:
<% #blog.order("created_at DESC").each do |d| %>
<!-- Blog Card -->
<div class="col-12 mb-3 mb-sm-7">
<article class="row align-items-lg-center">
<div class="col-lg-8">
<%= image_tag d.image.to_s, class:"img-fluid rounded" %>
</div>
<div class="col-lg-4">
<div class="py-5 px-lg-3">
<span class="d-block mb-2">
<p class="small text-body font-weight-bold text-cap"><%= d.tag_list %></p>
</span>
<h2>
<%= link_to d.title, d, class:"text-inherit" %>
</h2>
<p><%= d.summary.truncate(100) %></p>
<%= link_to "read more", d %>
</div>
</div>
</article>
</div>
<!-- End Blog Card -->
<% end %>
I want the code to change every nth time so i have multiple "layouts" (not in the ruby sense) in my blog. for this i added an if clause with following code:
<% if d.id % 5 == 0 %>
Unfortunately that does not work very well since i want to weave in the layout alternative into the regular layout like this:
┌─────────┐
└─────────┘
┌──┐┌──┐┌─┐
└──┘└──┘└─┘
┌─────────┐
└─────────┘
┌──┐┌──┐┌─┐
└──┘└──┘└─┘
So one large article, next row with three small ones etc.
Edit:
The alternating layout looks like this:
<div class="order-lg-1 col-sm-6 col-lg-4 mb-3 mb-sm-7">
<!-- Blog -->
<article
class="card align-items-start flex-wrap flex-row h-380rem gradient-y-overlay-sm-dark bg-img-hero rounded-pseudo transition-3d-hover"
style="background-image: url('<%= d.image.to_s %>');">
<div class="card-header border-0 bg-transparent w-100">
<p class="small text-white font-weight-bold text-cap mr-2"><%= d.tag_list %></p>
</div>
<div class="card-footer border-0 bg-transparent mt-auto">
<%= link_to d do %>
<h3 class="text-white"><%= d.title %></h3>
<span class="text-white-70">Read more<i class="fas fa-angle-right fa-sm ml-1"></i></span>
<% end %>
</div>
</article>
<!-- End Blog -->
</div>
How do i implement such a layout?
SOLUTION
I managed to do what i wanted with a combination of .each_with_index and using partials. like this:
<% #blog.order("created_at DESC").each_with_index do |d, index| %>
<%= index % 4 == 0 ? render("blog/var1", d: d) : render("blog/var2", d: d) %>
<% end %>

You can do something like this:
<% #blog.order("created_at DESC").each_with_index do |d, index| %>
<!-- Blog Card -->
<div class="col-#{index % 4 == 0 ? '12' : '4'} mb-3 mb-sm-7">
<article class="row align-items-lg-center">
<div class="col-lg-8">
<%= image_tag d.image.to_s, class:"img-fluid rounded" %>
</div>
<div class="col-lg-4">
<div class="py-5 px-lg-3">
<span class="d-block mb-2">
<p class="small text-body font-weight-bold text-cap"><%= d.tag_list %></p>
</span>
<h2>
<%= link_to d.title, d, class:"text-inherit" %>
</h2>
<p><%= d.summary.truncate(100) %></p>
<%= link_to "read more", d %>
</div>
</div>
</article>
</div>
<!-- End Blog Card -->
<% end %>
It means, for every 0, 4, 8, 12 .... index it'll add class col-12, otherwise it'll add class col-4
EDIT:
Yes, it is possible to insert whole partials as code:
Lets say, you created two separate files for small cards and big cards.
_small_blog_card.html.erb and _big_blog_card.html.erb
<% #blog.order("created_at DESC").each_with_index do |d, index| %>
<% if index % 4 == 0 %>
<%= render partial: 'big_blog_card', locals: {pass your data} %>
<% else %>
<%= render partial: 'small_blog_card', locals: {pass your data} %>
<% end %>
<% end %>

Related

Haiving a problem to Paginate an iteration with Kaminari

I'm trying to paginate a result of an iteration using Kaminari. The pagination is showing well but its not cutting it into another page. All is showing on the same page even when I click on page 2, it still the same result as page 1
I'm using rails 6 and ruby 2.5
in my controller i have this
def dashboard
user_gigs = current_user.gigs
#user_gigs_pager = Kaminari.paginate_array(user_gigs).page(params[:page]).per(4)
end
then in my view I call the paginate
<div class="card">
<div class="card-header-title is-centered">
<%= paginate #user_gigs_pager %>
</div>
</div>
this my full view code
<% current_user.gigs.each do |gig| %>
<%# <% user_gigs = current_user.gigs %>
<div class="column is-one-third">
<div class="card">
<div class="card-image">
<%= link_to edit_gig_path(gig) do %>
<figure class="image is-4by3">
<!-- Gig Cover Image Here -->
<%= image_tag gig_cover(gig) %>
</figure>
<% end %>
</div>
<div class="card-content p-t-5 p-b-5">
<p class="subtitle is-6 m-b-5"><%= link_to gig.title.truncate(20), gig_path(gig) %></p>
<span class="star-review"><i class="fa fa-star"></i>
<%= gig.average_rating %> <span class="star-review">(<%= gig.reviews.count %>)</span>
</span>
</div>
<footer class="card-footer">
<p class="deletegig">
<%= link_to destroy_gig_path(gig), method: :delete, data: { confirm: "are you sure"} do %>
<span class="icon has-text-danger">
<i class="far fa-trash-alt"></i>
</span>
<% end %>
</p>
<% basic_price = gig.pricings.find{ |p| p.pricing_type == 'basic' }%>
<a class="has-text-danger is-block card-footer-item has-text-right">
<% if !basic_price.nil? %>
<span class="small-title">Points</span> <i class="fab fa-bitcoin"></i>
<strong><%= basic_price.price %></strong>
<% else %>
<strong>
<span class="small-title has-text-dark">Pas de point</span>
</strong>
<% end %>
</a>
</footer>
</div>
</div>
<% end %>
</div>
</div>
</div>
<div class="card">
<div class="card-header-title is-centered">
<%= paginate #user_gigs_pager %>
</div>
</div>
Kaminari.paginate_array(user_gigs).page(params[:page]).per(4)
expects page number as argument of page and number of records per page as argument of per.
Your params must contain page number (i.e. 1 or 2 or 3 ...) in :page key.
The solution was to apply the pagination on the ActiveRecord association instead of the array.
So in my controller it should be
#user_gigs_pager = current_user.gigs.page(params[:page]).per(4)
then in the view
<% #user_gigs_pager.each do |gig| %>
....
<%= paginate #user_gigs_pager %>

Display last record in erb Rails with will_paginate

I am trying to display the last instanced record from my model Tribune with this layout :
Some random tribune
Some random tribune
Last
Last recorded tribune
I am using the gem will_paginate which allow me to display 10 tribunes / per page.
The issue is that the layout is working but applied to each page.
Every 10 tribunes, one is identified as "last". Obviously, I would like to have only one tribune identified as last.
Here is my code :
<div class="wrapping">
<% #tribunes.each do |tribune| %>
<div class="container">
<div class="mouse-out-container"></div>
<div class="row">
<% if tribune == #tribunes.last
%>
<h1>Last</h1>
<div class="col-xs-12 col-md-12">
<div class="card">
<div class="card-category">Popular</div>
<div class="card-description">
<h2><%= tribune.title %></h2>
<p><%= tribune.content.split[0...25].join(' ') %>...</p>
</div>
<img class="card-user" src="https://kitt.lewagon.com/placeholder/users/tgenaitay">
<%= link_to "", tribune, :class => "card-link" %>
</div>
<% else %>
<div class="col-xs-12 col-md-12">
<div class="card">
<div class="card-category">Popular</div>
<div class="card-description">
<h2><%= tribune.title %></h2>
<p><%= tribune.content.split[0...25].join(' ') %>...</p>
</div>
<img class="card-user" src="https://kitt.lewagon.com/placeholder/users/tgenaitay">
<%= link_to "", tribune, :class => "card-link" %>
</div>
</div>
<% end %>
<% end %>
</div>
<div class="center-paginate">
<%= will_paginate #tribunes, renderer: BootstrapPagination::Rails %>
</div>
</div>
</div>
When all Goole-fu fails, we have to dig in the source code. There we find some interesting methods:
# Any will_paginate-compatible collection should have these methods:
# current_page, per_page, offset, total_entries, total_pages
#
# It can also define some of these optional methods:
# out_of_bounds?, previous_page, next_page
From these, the method next_page looks interesting, as it seems to return nil if there are no more pages.
Now we can construct the loop:
<% #tribunes.each do |tribune| %>
<% if !#tribunes.next_page && tribune == #tribunes.last %>
<!-- We're on the last page and the last tribune of that page -->
Last tribune content
<% else %>
<!-- We still have tribunes to go -->
Normal tribune content
<% end %>
<% end %>

Trying to link reviews users actively input under the show page of the specific movie for which the review was written

Under app->controllers->reviews_controller.rb, I have the following code:
`def create
review = Review.new
review.movie_id = params["movie_id"]
review.rating = params["rating"]
review.content = params["content"]
review.save
redirect_to "/reviews"
end
I think that I need to use this information to link a review a user makes in real time to the view page for the movie (just basically building a mini IMDB page with about 12 movies currently)app->views->movies->show.html.erb.
<h2>Reviews</h2>
Do I need to use a params hash with "redirect_to" for the params["content"] above?
I hope this post is helpful to others seeking to gather user data and show in real time on the correct page.
This is reviews->index.
<h1>Reviews</h1>
<% for review in Review.order('created_at desc') %>
<% movie = Movie.find_by(id: review.movie_id) %>
<% if movie != nil %>
<div class="row mb-3">
<div class="col-sm-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">
<% 1.times do %>
<p>Howdy!</p>
<% end %>
★ ★ ★ ★ ★ ★
<p>
<%#= review.updated_at.strftime("%B %d, %Y %l:%M %P") %>
<%= time_ago_in_words(review.updated_at) %> ago.
</p>
<h6 class="card-subtitle mb-2 text-muted">
<%= movie.title %>
</h6>
</h5>
<p class="card-text">
<%= review.content %>
</p>
</div>
</div>
</div>
</div>
<% end %>
And this is the movies->show.
<% movie_id = params[:id] %>
<% movie = Movie.find_by(id: movie_id) %>
<div class="row">
<div class="col-sm-6">
<h2>
<%= movie.title %>
</h2>
</div>
</div>
<div class="row">
<div class="col-sm-3">
<img src="<%= movie.poster_url %>" class="img-fluid">
</div>
<div class="col-sm-6">
<a href="/movies/<%= movie.id %>/edit" class="float-right">
<i class="fas fa-pen-square"></i>
Edit This Movie
</a>
<% director = Director.find_by(id: movie.director_id) %>
<% if director != nil %>
<p>
Directed by <%= director.name %>
</p>
<% end %>
<p class="lead">
<strong><%= movie.plot %></strong>
</p>
<div class="row mt-3">
<% characters_in_this_movie = Character.where(movie_id: movie.id) %>
<% characters_in_this_movie.each do |character| %>
<% the_actor = Actor.find_by(id: character.actor_id) %>
<div class="col-sm-3 text-center">
<%= image_tag(the_actor.photo_url, class: 'img-fluid mb-3') %>
<br>
<strong><%= the_actor.name %></strong>
<br>
as <%= character.name %>
</div>
<% end %>
</div>
</div>
</div>
<div class="row mt-5 justify-content-center">
<div class="col-sm-6">
<a href="/reviews/new?movie_id=<%= movie.id %>" class="float- right">
<i class="fas fa-pen-square"></i>
Write a Review
</a>
<h2>Reviews</h2>
</div>
</div>

Rails partial view repeat display

Here is part of my index.html
<div class="col-md-8">
<% #books.each do |book| %>
<div class="row">
<div class="col-md-4">
<%= image_from_amazon(book.amazon_id) %>
</div>
<div class="col-md-8">
<h3 class = "text-info">
<%= book.title %>
</h3>
<br>
<em class ="text-muted">
written by <%= book.author %>
</em>
<br>
<br>
<p>
<%= book.description %>
</p>
<% book.genres.each do |genres| %>
<span class="label label-primary">
<%= genres.name %>
</span>
&nbsp
<% end %>
</div>
</div>
<% end %>
</div>
Basically, it will display 3 books, and it works fine.
Then, I move that code into _book.html.erb and edit above code into
<%= render #books %>
However, it repeat 3 times, that is, it display 9 books. And the sequence is [1st,2nd,3rd] [1st,2nd,3rd] [1st,2nd,3rd] like this picture.
Update
update index.html.erb
<div class="clearfix">
<div class="col-md-12">
<%= render #books %>
<div class="col-md-4">
<h3>Genre (Click to filter books)</h3>
<br>
<li>
<span class = 'label label-danger'>
<%= link_to "No filter" ,books_path, style: 'color:#FFFFFD' %>
</span>
<br>
<br>
</li>
<% #genres.each do |genres| %>
<li>
<span class = 'label label-primary' style="color:#FFFFFD">
<%= link_to genres.name ,books_path(filter: genres.name),style: 'color:#FFFFFD' %>
</span>
</li>
<br>
<% end %>
</div>
</div>
<!-- clearfix -->
</div>
Try the following:
<div class="col-md-8">
<%= render #books %>
</div>
And make sure <% #books.each do |book| %> and its <% end %> tag aren't in the partial.
Rendering Collections Docs
Edit
#index.html.erb
<div class="col-md-8">
<%= render #books %>
</div>
# _book.html.erb
<div class="row">
<div class="col-md-4">
<%= image_from_amazon(book.amazon_id) %>
</div>
<div class="col-md-8">
<h3 class = "text-info">
<%= book.title %>
</h3>
<br>
<em class ="text-muted">
written by <%= book.author %>
</em>
<br>
<br>
<p>
<%= book.description %>
</p>
<% book.genres.each do |genres| %>
<span class="label label-primary">
<%= genres.name %>
</span>
&nbsp
<% end %>
</div>
</div>

How do I detect the first iteration within my view? (Rails 4)

In my view I have:
<div class="item active">
<%= image_tag "2.jpg",size: "500x300", class: "no-resize" %>
<div class="carousel-caption">
Some tag.
</div>
</div>
<% #photos.each do |photo|%>
<div class="item">
<%= image_tag photo.attachment.url,size: "500x300",class: "no-resize" %>
<div class="carousel-caption">
Some tag.
</div>
</div>
<% end %>
Is there DRYer way of accomplishing this (as the only change I make is adding the class 'active' for the first photo) i.e. can I put the first item within the loop and detect the first iteration?
Try each_with_index
<% #photos.each_with_index do |photo, i |%>
<div class="item <%= "active" if i.zero? %>">
<%= image_tag photo.attachment.url,size: "500x300",class: "no-resize" %>
<div class="carousel-caption">
Some tag.
</div>
</div>
<% end %>
['apple', 'orange', 'pear'].each_with_index do |fruit, index|
p "first is #{fruit}" if index == 0
p fruit
end

Resources