Determine index of element in Array.each - ruby

I'm trying to render a bulk of content in rows of three. However, I'm not sure how would I determine the current position of the element using Ruby. This is what I have:
<% Animals.each do | animal | %>
<%= animal.species %>
<% end %>
I want to be able to add a <BR> or if I was rendering a table a </TR><TR> each time we'd hit the third animal in the set. Of course, if the number of elements nE isn't divisible by three, then the table would be malformed. I figured by doing a bit of checking after the iteration that I could close it.
But is there a way to get the index of an element that's being iterated over in an Array.each method? I have the strong hunch that I could just do the following:
<table>
<% Animals.each do | animal | %>
<% if Animals.find_index(animal) / 3 == 0 %>
<tr>
<% end %>
<td><%= animal.species %></td>
<% if Animals.find_index(animal) / 3 == 2 %>
</tr>
<% end %>
</table>
My only thing is that Animal is a subclass of ActiveRecord::Base, so I'm not sure (haven't looked to see) if this would scale well, let alone if each call to find_index would be a super intensive method. Any suggestions are welcome.

You need
<% animals = Animals.all %>
<table>
<% animals.in_groups_of(3) do |animal_row| %>
<tr>
<% animal_row.compact.each do |animal| %>
<td><%= render animal %></td>
<% end %>
</tr>
<% end %>
</table>
Should roughly do the job.
More importantly, I think keeping the Enumerable module's documentation handy has been great for me as a Ruby developer. It is my "favourite" module, and nearly ALWAYS helps me solve tricky problems easily.

Related

How to list(<li>) data from a column in a table having newlines(\r +) inside ruby tag?

My code is
#tariff.each do |tar|
<li><%= tar.lt_ninety%></li>
<%end%>
This lt_ninety has a value (hey hello) contain new line(\r +) in between each word in table.
I have found one method in Stack Overflow, but couldn't help me to solve.
<li><%= h(tar.lt_ninety).gsub(/\r/, '<br/>').html_safe%></li>
and output was like
<li> hey</li>
hello
I cannot wrap hello in <li>
Split up tar.lt_ninety and loop it
<% #tariff.each do |tar| %>
<% tar.lt_ninety.split(/\r/) do |ln|%>
<li><%= h ln %></li>
<% end %>
<%end%>
Just split tar.lt_ninety into separate lines before generating a <li> for each line:
<% #tariff.each do |tar| %>
<% tar.lt_ninety.lines.each do |line| %>
<li><%= line %></li>
<% end %>
<%end%>
Hurray!! my colleague gave me a cool solution
<ul><% (tar.lt_ninety).split(/\r\n/).each do |val| %>
<li><%= val %></li>
<% end%></ul>

simple_form - can't generate combined select input

I have complex form with a lot of controls, and I'm currently using simple_form gem due to its flexibility. But when I wanted to do something more complex I faced to several problems that currently looking obscure for me. I would like to introduce combined collection input, that will render both optgroups and single non-groupped selects. Generated html that I want to achieve should look something like this:
<select name="select" multiple="multiple">
<option value="1">Milk</option>
<optgroup label="Soda">
<option value="2">Cola</option>
<option value="3">Fanta</option>
</optgroup>
</select>
I've tried to create custom input class, but stucked on implementation details of input method, I simply couldn't find out how to generate proper output.
UPDATE
Currently quick and dirty implementation for custom input looks something like this, but I don't think that it is a good idea to drop all goodnesses with options that simple_form gives me.
class CombinedMultiselectInput < SimpleForm::Inputs::CollectionSelectInput
include ActionView::Helpers::FormTagHelper
include ActionView::Helpers::FormOptionsHelper
def input
out = ActiveSupport::SafeBuffer.new
option_tags = ungrouped_options.safe_concat(grouped_options)
out << select_tag(options[:name], option_tags, class: ['select', 'form-control'])
out
end
private
def ungrouped_options
# this can be retrieved from general collection like collection[:ungrouped]
collection = [["Foo", 2], ["Bar", 3]]
options_for_select(collection)
end
def grouped_options
# and this using collection[:grouped]
collection = [["Group", [["Foobar", 4]]]]
grouped_options_for_select(collection)
end
end
Using your current design you can combine the options_for_select and option_groups_from_collection_for_select methods like so.
def ungrouped_options
[["Foo", 2], ["Bar", 3]]
end
def grouped_options
[["Group", [["Foobar", 4]]]]
end
def your_hash
{"ungrouped" => ungrouped_options, "grouped" => grouped_options}
end
Then in your view something like this should work:
<%= content_tag(:select,nil,{multiple: true,name: "select"}) do
<%= your_hash.each do |k,v| %>
<% if k == "ungrouped" %>
<%= options_for_select(v) %>
<% else %>
#this works because:
# last will be the collection of children for a member
# first will be the group name
# last on the child will be the value method
# first on the child will be the text displayed
<%= option_groups_from_collection_for_select(v, :last, :first, :last, :first) %>
<% end %>
<% end %>
<% end %>
This will create the following:
<select name=\"select\" multiple=\"true\">
<option value=\"2\">Foo</option>
<option value=\"3\">Bar</option>
<optgroup label=\"Group\">
<option value=\"4\">Foobar</option>
</optgroup>
</select>
Obviously this was simplified to show how this could be done but hopefully this points you in the right direction.
You should also be able to wrap this for simple_form although I have not tested it.
<%= f.input :some_attribute do %>
<%= f.select :some_attribute do %>
<%= your_hash.each do |k,v| %>
<% if k == "ungrouped" %>
<%= options_for_select(v) %>
<% else %>
<%= option_groups_from_collection_for_select(v, :last, :first, :last, :first) %>
<% end %>
<% end %>
<% end %>
<% end %>

Ruby .each but need to add in a unique class for each of them

i have the following piece of code that loops through and shows the results however i want to be able to set a class for each of the <td> and unsure how to do this as i dont know ruby and doing the frontend on a ruby project.
<% priority[1].each do|val|%>
<td><%=val[1] %></td>
<% end %>
It just shows 4 of them so if i can set defined classes great but if not something like class1, class2, class3, class4 would be fine i guess.
Many Thanks
You could do this:
<% priority[1].each_with_index do |val,i| %>
<td class="class<%= i %>"><%= val[1] %></td>
<% end %>
Which will give every element a unique class of 'class1','class2' etc for all i.
Marginally more complicated, but this example allows you assign your own class names:
<% arr = ['Hi','Hello','Howdy','Yo'] #class names %>
<% priority[1].each_with_index do |val,i| %>
<td class="<%= arr[i] %>"><%= val[1] %></td>
<% end %>

Ruby each, different action depending on index, with a pattern?

Ok so my title may be confusing. What I want to do is to loop through a collection of models, and for the first two, render a template, for the next four render a different template and next two render the same template as for the first ones, and so on.
Like this:
<% ads.each do |ad| %>
<% # if it's 1-2, 7-8, 13-14 and so on render as big' %>
<%= render 'front/home/big_ad', ad: ad %>
<% # if it's 3-6, 9-12, 15-18 and so on render as small' %>
<%= render 'front/home/small_ad', ad: ad %>
<% end %>
<% end %>
What would be the cleanest way to accomplish this?
If your groups would be even long, then you could use in_groups_of command, and alternate between them, but with these specifications, the easiest way is this:
<% ads.each_with_index do |ad, index| %>
<% if (index % 6 < 2) %>
<%= render 'front/home/big_ad', ad: ad %>
<% else %>
<%= render 'front/home/small_ad', ad: ad %>
<% end %>
<% end %>

Sorting and manipulating a hash in Ruby

In my rails 3.1 project I have a Book model that has a ID, NAME, and BOOK_ORDER. I am using the ranked-model gem, which for its sorting process creates large numbers in the sorting(:book_order) column. Im looking for some help to create a method to sort all of the Books by the :book_order column, then simplify the :book_order numbers.
So, I have this:
controller
#books = Books.all
view
<% #books.each do |book| %>
<%= book.book_order %>
<% end %>
# book1.book_order => 1231654
# book2.book_order => 9255654
# book3.book_order => 1654
But want this:
view
<% #books.each do |book| %>
<%= book.clean_book_order %>
<% end %>
# book1.clean_book_order => 2
# book2.clean_book_order => 3
# book3.clean_book_order => 1
Additionally, i don’t want to change the database entry, just use its current values to make simpler ones.
Thanks!
UPDATE:
Thanks to nash’s response I was able to find a solution:
In my Book Model I added the clean_book_order method:
class Book < ActiveRecord::Base
include RankedModel
ranks :book_order
def clean_book_order
self.class.where("book_order < ?", book_order).count + 1
end
end
<% #books.each do |book| %>
<%= book.book_order_position %>
<% end %>
EDIT:
Oh, I see. https://github.com/harvesthq/ranked-model/issues/10

Resources