Ruby each do loop 'n' number of times - ruby-on-rails

Hi I'm having trouble with the below loop in a .erb view
<% my_list.each do | list | %>
.. loop stuff.....
<% end %.
This works fine for looping through my list, but I only want to loop through the first 4 items in 'my_list' and not the whole list. I tried some things like:
<% my_list.each do | product | 3.times %>
but didn't seem to work as I think my ruby knowledge is limited to say the least!

Use Array#take like this:
<% my_list.take(4).each do | product | %>

Take first 4 element from my_list Array#first:
<% my_list.first(4).each do | product | %>
use Array#each_slice for slice your array
<% my_list.each_slice(4) do | products | %>
<% products.each do | product | %>

It is apparent that you want to iterate through your list in groups of four (you really should amend your question, because this is an important piece of information). It is also apparent you are using Rails. Fortunately Rails has in_groups_of built into ActiveSupport:
<% my_list.in_groups_of(4) do |products| %>
<% products.each do | product | %>
One advantage of this approach (over alternatives such as each_slice) is that in_groups_of will pad the end to make sure you always get four groups. It will pad with nil by default, but you can specify the padding yourself:
<% my_list.in_groups_of(4, " ") do |products| %>
If you pass false as the pad, it will not pad at all and behaves just like each_slice.

<% my_list[0..3].each do | list | %>

Related

Ruby enumerable block variable assignment

Given this ERB code
<% #client.sessionables.ordered.by_program_completion.reverse_each do | program_name_and_completion, sessionables | %>
<% program_name, program_completion_date = program_name_and_completion %>
<% # Render stuff... %>
<% end %>
I would like to get rid of the second line, where I use the multiple variable assignment to extract program_name and program_completion_date from the program_name_and_completion array. One would assume it could be done directly in the block assignment, e.g.
sessionables.by_program_completion.each do | [program_name, program_completion_date], sessionables |
but the above snippet doesn't work, so my questions are:
Is this at all possible with Ruby?
If so, what's the correct syntax?
You can extract the arguments inline as follows:
<% #client.sessionables.ordered.by_program_completion.reverse_each do |(program_name, program_completion_date), sessionables| %>
Or to write the same thing using less verbose syntax (so it's easier to see what's going on!!):
[[[1, 2], 3]].each { |(a, b), c| ... }
Inside the block, we get: a == 1, b == 2, c == 3.

Getting the winner of a match - the rails way?

In my (League) view I want to list all the matches and mark the match as played, the winning team or the match as a tie.
To know if it is a tie or who the winner is, I have to check the score of each opponent. Where do I do these calculations? view helper?, model scope?
My idea is to have three functions that check per match when i list the matches:
match.played? -> true / false
match.tie? -> true / false
match.winner? -> team_id with the highest score.
Database (postgresql)
Matches
id | league_id | date
---+-----------+----------
1 | 1 | 2016-03-21 21:00:00
2 | 1 | 2016-03-22 09:00:00
...
Opponents
(score is null if not played)
id | match_id | team_id | score
---+----------+---------+--------
1 | 1 | 1 | 0
2 | 1 | 2 | 1
3 | 2 | 3 | 1
4 | 2 | 4 | 1
4 | 3 | 1 |
4 | 3 | 2 |
....
You're definitely on the right path. I would have the methods you suggested on my Match model with one exception:
match.winner #=> returns the Team object of the winner (or nil).
I would then have a view helper that called these methods to determine how to render them. I.e., Has it been played? Was it a tie? Who won.
Your questions scope is a little broad for a definitive answer ;)
Ask 5 developers and you will get 12 different answers.
That said, here is what I would do:
Your idea to implement those instance methods is a good starting point, although I personally do not like "?" methods that do not return a boolean value, in my oppinion it should just be #winner and should return the team instance, not the id (I take it there is a "Team" model). You might want to think about a complementary #loser method.
Your view could look something like this:
<table>
<% #matches.each_with_index do |match, i| %>
<tr>
<td class="match number">
<%= i + 1 %>
</td>
<td class="team-1">
<%= match.team_1 %>
</td>
<td class="team-2">
<%= match.team_2 %>
</td>
<td class="winner">
<% if match.played? %>
<!-- this would be a view helper since you have to consider
the tie situation and we do not want that much logic
in the view. It would return a string with either the
teams name or "tie". -->
<%= winner_of_match match %>
<% else %>
N/A
<% end %>
</td>
<!-- etc... -->
</tr>
<% end %>
</table>
This is just very basic to give you an idea to build on. For example you might want to get rid of the if match.played and do it in your view helper (return "not yet played" or something).

Setting page titles as attribute values with Rails

I'm wondering if anyone knows to how to set a page's title to an attribute.
Was thinking something along the lines of:
<% content_for :title, "Museum | '#gallery.name'" %>
But I cant figure out what to wrap #gallery.name in, if this is even the right approach.
It's probably a really simple question, but I seem to be stumped!
maybe?
<% content_for :title do %>
(#gallery && #gallery.name) || 'Museum'
<% end %>
of course yield :title somwewhere is required
credits to #Clark
if the text should be Museum | foobar if #gallery name exists then instead of
(#gallery && #gallery.name) || 'Museum' it should be
"Museum | #{#gallery && #gallery.name} (in case #gallery is always guaranteed to be defined even simplier "Museum | #{#gallery.name}" (remember to use double " not ').

Would adding a dynamic tooltip affect load time?

I have a table "State", consisting of a few thousand records, and I'm printing each of their names on one page. Would adding a dynamic tooltip to each add noticeably to the load time of the page? In other words, would there be a significant performance difference between these two blocks of code?
<%= State.all.each do |state| %>
<%= state.name %>
<% end %>
or
<%= State.all.each do |state| %>
<%= link_to state.name, "#", title: "(" + state.weather + ")" %>
<% end %>
For the record, weather is a instance method calculated by adding two State attributes together:
def weather
self.snow + self.rain
end
If you want to know you can easily check the log, it shows you the active record time and the view rendering time
It would look something like this
Completed 200 OK in 539ms (Views: 486.9ms | ActiveRecord: 1.8ms)
The first 200 means that the request was a success, the 2nd number 539ms is the total request time, which in this case is '539 milliseconds', then there's a break down of that time, 486.9ms was spent in the view rendering, and 1.8ms is spent in the ActiveRecord queries
Test both cases, I don't think you'll find any huge difference but you should check
PS: you should move the query call to the controller, just for good convention
# controller
#states = State.all
#view
<%= #states.each do |state| %>

How to group a list of symbols or numbers into a # symbol

I am trying to create a glossary of terms ordered alphabetically like this example:
-A-
Alpha
ATM
-B-
Beta
...
I have no problem to group terms by letter but I wonder how I can manage symbol and digits in order to group them through a # symbol
-#-
52 weeks low
#test
I figured out to add a column in my Term table where I specify the first letter (in the symbol case I would select a "#" in a select box for example) but I would be pleased to know if there is a better way to achieve this without adding another field.
As info, here is my controller:
#terms = Term.all.group_by{|t| t.name[0]}
and my view:
<% #terms.keys.sort.each do |first_letter| %>
<%= first_letter %>
<% #terms[first_letter].each do |term| %>
<%= term.name %>
<% end %>
<% end %>
Thanks for your help!
You can do it like this, might be a performance hit, but gets the job done:
#terms = Term.all.group_by{|t| t.name[0].capitalize.match(/[A-Z]/) ? t.name[0].capitalize : "#" }

Resources