How can I display every 4th product with different markup? - ruby-on-rails

I'm just starting out with Ruby from a java background. I'm trying to code a particular loop but can't figure out the right syntax:
Could someone help me troubleshoot this please? I'm trying to write a loop but use different css classes to change the style of each block.
Realise this is probably easy, but help is appreciated....
<%= #products.each do |product, i| %>
<% if i % 1 %>
<div class="items-row clearfix">
<div class="one_fourth">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>
<p class="color-wrap">
<span class="color" style="background:#ddd;"></span>
<span class="color" style="background:#f9f9f9;"></span>
<span class="color" style="background:green;"></span>
<span class="color" style="background:red;"></span>
</p>
</div>
<% elsif i % 4 %>
<div class="one_fourth last">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>
</div>
</div><!-- end row -->
<% else %>
<div class="one_fourth">
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p>Item Name</p>
<p class="bold">$79.95 AUD</p>
</div>
<% end %>
<% end %>

You can do something like this using cycle:
<% products.each_slice(4) do |slice| %>
<div class="items-row clearfix">
<% slice.each_with_index do |product,i| %>
<div class="one_fourth <%= cycle("first", "second", "third", "fourth") %>">
<%= render product %>
<% if i != 3 %>
<p class="color-wrap">
<span class="color" style="background:#ddd;"></span>
<span class="color" style="background:#f9f9f9;"></span>
<span class="color" style="background:green;"></span>
<span class="color" style="background:red;"></span>
</p>
<% end %>
</div>
<% end %>
</div>
<% end %>
_product.html.erb:
<div class="item-thumb">
<img src="<%= image_path "thumb.png" %>" alt="" class="thumb" width="162" height="230" />
</div>
<p><%= product.name %></p>
<p class="bold">$79.95 AUD</p>

Rather than if/else statements and CSS markup in your views, you should probably externalize your CSS, make a few partials, and make use of ActionView::Helpers::TextHelper#cycle. For example:
<%= #products.each do |product| %>
<div class="<%= cycle('first', 'second', 'third', 'fourth') -%>">
<!-- 1. let the CSS class handle display differences -->
<!-- 2. render a partial based on #current_cycle -->
<%= render :partial => current_cycle %>
</div>
<% end %>

I'd say the mod's are your problem. It's never going to go into the first block as n%1 will always return 0. Try your logic out using irb to get you going.

You may want to try jQuery nth-child

I got part of the answer. Slight change of syntax to use "each_with_index" instead of just each.
Still trying to work out there's a lot of variations of when a product can be the last tile and require closing, first on row, first in set, last in a row.....
Thanks guys, I think I've answered my own question.

Related

Rails stimulus one form change for many urls and turbo frames

I am building a dashboard with multiple elements like charts, tables, simple fields with calculated values etc and I want to use Rails7 with stimulus.
In the past I used jQuery so I just created empty elements and then called several ajax requests in paralel to get data for every elements and populate it. So initial page load was super fast and then it loaded all necessary data. Dashboard had few dropdowns options to change data and when I loaded page I just sent defaults. Every dropdown change reloaded all data for all elements by filter used in dropdown.
How to do similar approach with stimulus?
When I use turbo form what I can do is submit form on page load, but it looks ugly (page initially loads and instantly reloads). And if I have many elements it gets slow because it first needs to finish all calculations.
this is my simple filter with 2 dropdowns
<%= form_with url: "", method: :get, data: { controller: "home", home_target: "form", turbo_frame: "home_dashboard", turbo_action: "advance" } do |form| %>
<div class="row">
<div class="d-sm-flex align-items-center mb-3">
<div class="col-lg-2" >
<%= form.select :city, options_for_select(City.all.pluck(:name,:id)), {include_blank: (t 'all')}, {class: 'form-select', data: {action: "input->home#search"}} %>
</div>
<div class="col-lg-2" >
<%= form.select :year, options_for_select(#years.reverse, (params[:year] || Date.today.year)), {selected: params[:year], include_blank:false}, {class: 'form-select', data: {action: "input->home#search"}} %>
</div>
</div>
</div>
<% end %>
and this is my home controller in stimulus which is simple
import { Controller } from "#hotwired/stimulus"
// Connects to data-controller="home"
export default class extends Controller {
connect() {
}
static targets = ["form"]
connect() {
this.formTarget.requestSubmit()
}
search() {
this.formTarget.requestSubmit()
}
}
my rails controller gets ugly big because I am calculating lot of fields dynamically and showing them in turbo frame tag...this is just a part of data I want to show so there should be much more
<%= turbo_frame_tag "home_dashboard" do %>
<div class="row">
<div class="col-xl-6">
<div class="card border-0 mb-3 overflow-hidden ">
<div class="card-body">
<div class="row">
<div class="col-xl-7 col-lg-8">
<div class="mb-3 fs-13px">
<b><%= (t 'invoices.invoiced').upcase %></b>
</div>
<div class="d-flex mb-1">
<% if #invoices_sumed.present? %>
<h2 class="mb-0"><span data-animation="number" data-value="<%= #invoices_sumed[0][1] %>"><%= #invoices_sumed[0][1] %></span> <%= #invoices_sumed[0][0] %></h2>
<% else %>
<h2 class="mb-0"><span data-animation="number" data-value="0">0</span> EUR</h2>
<% end %>
</div>
<div class="mb-3">
<i class="fa fa-caret-up"></i> <span data-animation="number" data-value="<%= #invoices_sumed_compare %>"><%= #invoices_sumed_compare %></span>% <%= t 'invoices.compared_previous_year' %>
</div>
<hr>
<div class="row text-truncate">
<div class="col-6">
<div class=""><%= t 'invoices.total' %></div>
<div class="fs-18px mb-5px fw-bold" data-animation="number" data-value="<%= #invoices.size %>"><%= #invoices.size %></div>
<div class="progress h-5px rounded-3 mb-5px">
<div class="progress-bar progress-bar-striped rounded-right " data-animation="width" data-value="<%= calc_year_ratio(#invoices.size,#invoices_total_size) %>%" style="width: <%= calc_year_ratio(#invoices.size,#invoices_total_size) %>%;"></div>
</div>
</div>
<div class="col-6">
<div class=""><%= t 'invoices.average' %> <small>(<%= (t 'invoices.median').to_s + ":" %> <strong><%= "#{#invoices_median_value.round(2)} #{#invoices_top_currency}" %></strong>)</small></div>
<div class="fs-18px mb-5px fw-bold"><span data-animation="number" data-value="<%= #invoices_avg_value.round(2) %>"><%= #invoices_avg_value.round(2) %></span> <%= #invoices_top_currency %></div>
<div class="progress h-5px rounded-3 mb-5px">
<div class="progress-bar progress-bar-striped rounded-right bg-orange" data-animation="width" data-value="<%= calc_median_total_ratio(#invoices_avg_value,#invoices_max_value) %>%" style="width: <%= calc_median_total_ratio(#invoices_avg_value,#invoices_max_value) %>%;"></div>
</div>
</div>
</div>
</div>
<div class="col-xl-5 col-lg-4 align-items-center d-flex justify-content-center">
<canvas
data-controller="chart"
data-chart-data-value='<%= #chart_total.to_json %>'
data-chart-options-value="<%= #chart_options.to_json %>"
></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="table-responsive">
<table id="contractors" class="table table-hover align-middle" style="width:100%;">
<thead></thead>
<tbody>
<% #contractors.each do |contractor| %>
<tr>
<td><%= contractor[0]%></td>
<td><%= contractor[2]%></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<% end %>
is there any way how to split this in multiple turbo frames with multiple urls to call with one form select change?

Is there a conflict with this code and FancyBox3?

Can anyone tell me whats wrong with this section of code? I recently got this to work, but found out soon after the functionality for the Fancybox gallery stopped working. The a link element is only a sliver compared to the over all element. Im not sure if thats it. I know the most recent edit I made was to fix the surrounding row from .row-fluid to .row since that broke my layout. Below is the code:
<body id="portfolio">
<div class="container-fluid" id="particles-js"></div>
<%= render 'layouts/altmenu_gallery' %>
<h1>Portfolio</h1>
<div id="gallery" class="container-fluid">
<% #photos.each_slice(4) do |group| %>
<div class="row ">
<% group.compact.each do |photo| %>
<div class= "col-md-3">
<a class="fancybox" data-fancybox="gallery" href="<%=image_path photo.file_url %>" data-caption="<%= photo.description %>">
<%= image_tag photo.file_url, class:' img-fluid img-thumbnail' if photo.file.present? %>
</a>
</div>
<% end %>
</div>
<% end %>
<br class="clear">
</div>
<%= link_to 'New Photo', new_photo_path %>
</body>
Sorry, but it is not possible to tell without seeing the actual html code or, preferably, live demo. Maybe this issue arises because you have not escaped photo.description and that breaks html code, but, as I said, I can not be sure.

Rails/BootStrap - Make iterated object data appear in columns

I am trying to get my cards to show-up as three in a row and then jump to the next line and put the next three. Right now, it's just putting each card right below the one above it. Can anyone help me out?
<div class="container">
<div class="row">
<div class="col-md-6">
<% #block_busters.each do |movie| %>
<div class="card" style="width: 20rem;">
<img class="card-img-top" src="<%= movie.image_url %>" alt="Card image cap">
<div class="card-body">
<h4 class="card-title"><%=movie.title%></h4>
<p class="card-text"><%=movie.description%></p>
</div>
</div>
<%end%>
</div>
</div>
</div>
You're most likely looking for the 'slice' method, try something like this:
<% #block_busters.each_slice(3) do |slice| %>
<div class="row">
<% slice.each do |movie| %>
<div class="col-md-4"> <!-- 12 cols / 3 cards = 4 -->
<!-- render your cards here, each will show up in rows of 3 -->
</div>
<% end %>
</div>
<% end %>

Rails HTML embedding not working correctly

so I'm trying to show some blog-type data on one of my pages. It works fine, but is posting the posts all at the end of the div as well.
Like this:
Image
<div class="style-2 mb-20 shadow bordered light-gray-bg news-margin col-md-5">
<!-- page-title start -->
<!-- ================ -->
<h1 class="page-title">Latest News</h1>
<div class="separator-2"></div>
<!-- page-title end -->
<p class="lead">The latest news will be posted here:</p>
<div class="row grid-space-12">
<%=# news.each do |news| %>
<div class="col-sm-12">
<div class="image-box style-2 mb-20 shadow bordered text-center">
<div class="overlay-container">
<i class="fa fa-newspaper-o fa-5x p-20"></i>
<div class="overlay-to-top">
<p class="small margin-clear"><em> <%= news.topic %> <br> <%= news.created_at.strftime("%A, %b %d") %></em>
</p>
</div>
</div>
<div class="body">
<h3><%= news.header %></h3>
<div class="separator"></div>
<p>
<%=n ews.content %>
</p>
Read More<i class="fa fa-arrow-right pl-10"></i>
</div>
</div>
</div>
<% end %>
</div>
</div>
Figured it out, I had the = in with <%= news.each do |news| %>, which was printing that info out...

How do I add left and right classes to every other element in a loop in Ruby on Rails?

I am working within a Ruby on Rails app. I have a loop that creates divs like this:
<% #snorks.each do |snork| -%>
<div>
<%= snork %>
</div>
<% end %>
And I need the output to have every other div be floated left or right like this:
<div class="left">
Allstar Seaworthy
</div>
<div class="right">
Casey Kelp
</div>
<div class="left">
Dimmy Finster
</div>
<div class="right">
Daffney Gillfin
</div>
<div class="left">
Tooter Shellby
</div>
<div class="right">
Dr. / Uncle Galeo
</div>
Additionally, I need to add a div with class="clear" every two divs, like this:
<div class="left">
Allstar Seaworthy
</div>
<div class="right">
Casey Kelp
</div>
<div class="clear"></div>
<div class="left">
Dimmy Finster
</div>
<div class="right">
Daffney Gillfin
</div>
<div class="clear"></div>
<div class="left">
Tooter Shellby
</div>
<div class="right">
Dr. / Uncle Galeo
</div>
<div class="clear"></div>
I have researched, and found a few posts saying that the alternate classes can be accomplished easily by using cycle(), and that does work. However, when I use it in two places within the loop it stops working right and just outputs something like this:
<div class="left">
Allstar Seaworthy
</div>
<div class="left">
Casey Kelp
</div>
<div class="left">
Dimmy Finster
</div>
<div class="left">
Daffney Gillfin
</div>
<div class="left">
Tooter Shellby
</div>
<div class="left">
Dr. / Uncle Galeo
</div>
What's the best practices way in Ruby on Rails to alternate classes in a loop, and also add something every other loop?
According to the documentation, if you need nested ones you name them. Otherwise they will both share the name "default" and conflict.
<% #snorks.each do |snork| -%>
<div class="<%= cycle('left', 'right') -%>">
<%= snork %>
</div>
<%= cycle('','<div class="clear"></div>', :name=>"cleardiv") %>
<% end %>
The best thing here seems to be using each with index. That way you could do some simple modulus math to determine if the number is odd or even and output the correct class and add the clears.
#snorks.each_with_index do | snork, index|
If index%2 == 0
class = 'left'
else
class = 'right'
end
Well u get my drift and I'm on my phone.
use cycle helper
http://apidock.com/rails/ActionView/Helpers/TextHelper/cycle
<% #snorks.each do |snork| -%>
<div class="<%= cycle("left", "right") -%>">
<%= snork %>
</div>
<% end %>
Edit: for adding new div; following could help
<% #snorks.each_slice(2) do |snork_batch| -%>
<% snork_batch.each do |snork|%>
<div class="<%= cycle("left", "right",:name=>"className") -%>">
<%= snork %>
</div>
<%end%>
<div class="clear"></div>
<% reset_cycle("className")%>
<% end %>

Resources