Ruby 'First and Rest' Logic - ruby

My app is reaching a point where I must begin optimizing for performance. I've posted some code from my view that I feel can be improved.
In the view, I am treating the first item in the index a certain way and the rest of the items another way. Each time a new item is iterated over, it is being checked (Ruby asks itself.. does this item have an index of 0?)
I feel like performance can be improved if I can stop that behavior by treating the first item special with index.first? and treating the other items another way (without even checking whether they have an index of zero) How can this be done?
<% #links.each_with_index do |link, index| %>
<% if link.points == 0 then #points = "?" else #points = link.points %>
<% end %>
<% if index == 0 then %>
<h1> First Item </h1>
<% else %>
<h1> Everything else </h1>
<% end %>
<% end %>
<% end %>

You can do this non-destructively like so:
first, *rest = *my_array
# Do something with 'first'
rest.each{ |item| … }
…where first will be the first element (or nil if my_array was empty) and rest will always be an array (possibly empty).
You can get the same results more easily if it's OK to modify your array:
# remove the first item from the array and return it
first = my_array.shift
# do something with 'first'
my_array.each{ |item| … }
However, this will only clean up your code; it will make no measurable performance difference.

Related

Retrieve data using for loop in Ruby

I have a question about using foreach loops in Ruby.
I want to display documents and am using a foreach loop in order to display these documents. It returns an error with the i variable inside of data["response"]["docs"][i]["topic"] which is a JSON string I am iterating over.
I do not understand why that is. Can anyone tell me what I am doing wrong?
If I simply do data["response"]["docs"][0]["topic"] it works fine but not with the i. Why is that?
<%
(0..10).each do |i|
%>
<%= i %> <br/>
<%= data["response"]["docs"][i]["topic"] %>
<%
end
%>
My question is, how many items are there in data["response"]["docs"]? Are there exactly 11? Either way I would use the following code instead:
<% data["response"]["docs"].each_with_index do |item, index| %>
<%= index %>
<br/>
<%= item["topic"] %>
<% end %>
This iterates over the data["response"]["docs"] no matter how many there are (whether is is 1 doc or 20 docs) and stores the value in the variable named item. The each_with_index function gives you the index as well, stored in index, so you can display it later. If you only want the first 11 use:
<% data["response"]["docs"].first(11).each_with_index do |item, index| %>
This will grab a maximum of 11 doc items.
It's hard to tell what might be going wrong because you haven't posted the error, but if you're using a 10-element array, you want to do:
(0..9).each do |i|
With 0-based indexes, you should only use the range from 0-9, rather than 0-10. You may be getting an error because you're trying to access an element that isn't there (i.e. at index 10).
Even better is:
<% data["response"]["docs"].each do |document| %>
<%= document["topic"] %>
<% end %>
or if you need to print the index:
<% data["response"]["docs"].each_with_index do |document, index| %>
<%= index %> <br/>
<%= document["topic"] %>
<% end %>

Trying to break an array into three uneven arrays (Ruby on Rails)

Here's the code that will yield an array (I believe it's an array) of 13 page titles. I'd like to have titles 0-5 be in its own div, 6-8 in a second div and 9-12 in a third, for dropdown menus. I couldn't find this exact question/answer here.
<% #cms_site.pages.root.children.published.each. do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
Thank you!
What have you attempted? #each is not a very good use for this case. You might want to separate it into 3 different loops like so:
<% #cms_site.pages.root.children.published[0,5].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
<% #cms_site.pages.root.children.published[6,8].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
<% #cms_site.pages.root.children.published[9,12].each do |page| %>
<%= link_to page.label, page.full_path %>
<% end %>
EDIT
It seems like you're having some logic problems, it'd be wise for you to attempt it first at least.
The code up there should work but it's not really DRY and it can be extracted into maybe a helper method that uses the chapters for the iterator or possibly use a different iterator (e.g. each_with_index) and handle the check for each index in the block. There's many ways to go about doing what you asked.
Basically, if you're dealing with an array and you want to take the exact same elements from it each time, here's how to slice it:
# Your Array
elements = [1,2,3,4,5,6,7,8,9,10,11,12]
# This will give you three arrays inside one array. The first will be first six
# elements starting from 0, the second is 3 elements starting from 6, etc.
arrays = [ elements[0,6], elements[6,3], elements[9,3] ]
Now you can iterate through the array and reuse the code to generate the code you want.
arrays.each do |ar|
# Now render for each array as you please, and reuse the same code.
end

Redmine modification for issue number

I would like to hide the issue number on the issue list.
I use "Redmine 2.3.1" and the file to achieve that is this file: ./app/views/issues/_list.html.erb
It contains this line:
<%= raw query.inline_columns.map {|column| "<td class=\"#{column.css_classes}\">#{column_content(column, issue)}</td>"}.join%>
And the array query.inline_columns contains the id for example. I thought modifying this array would help me with my problem, but the changes aren't saved.
This is what I tried:
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
<% #query.inline_columns.delete_at(0) %>
=>
<%= #query.inline_columns.inspect %>
=> [#<QueryColumn:0x00000003607928 #name=:id ... and so on>]
Why was the delete_at useless? And how would I modify this array or hide the number?
A few things to note:
#query.inline_columns might not an array. It may quack like an Array, but it's not.
#query.inline_columns.delete_at(0) should have returned something. Did it return and you ommited?
And last, but not least, the most probable guess I can make:
#query.inline_columns fetches something, converts it to an array and dups it before returning. The only way you can do something like that would be:
some_columns = #query.inline_columns
some_columns.delete_at(0)
some_columns
This is my solution now:
<% if #project.id == 1 %>
<% #qcols = query.inline_columns.reject{ |col| col.name.to_s == 'id' } %>
<% else %>
<% #qcols = query.inline_columns.each %>
<% end %>
So I took advantage of the reject method. And then I work with the #qcols.
Posted on behalf of OP.

Puppet 3 loop execution only if variable is defined within a template

I am trying to create a loop only if index is defined. But it looks like
erb can't handle a loop within a if clause.
<% if(#index) %>
index <% index_files.each do |i| %> <%= i %> <% end %>;
<% end %>
Expected Result was:
index index.html index.php
or
""
Syntax error i got:
My flat approach failed as expected:
<% if(#index_files) %> try_files <% end %> <% index_files.each do |i| %> <%= i %> <% end %>
I defined index_files as undef => broke the each loop
I defined an empty array => since an empty array is defined it didn't work.
Maybe I can check the length of index_files?
Or do I need a complete different way to solve the problem?
I'm doing the same and it works for me, also for nginx ;).
For example:<% if #proxy_ignore_headers %> proxy_ignore_headers<% proxy_ignore_headers.each do |i| -%> <%= i %><% end -%>;
That works like a charm, the only difference with you is using () for the if condition, but I bet puppet supports (). It's weird, maybe you had pressed a bad combination generating a character that can't be seen but it's messing with your code, try writing all from scratch just in case.
You can see the full template here
Good luck
At first glance you just need to change
index_files.each
to
#index_files.each

Ruby Each Loop Variable Substitution

I'm trying to set all the values to 0 but the 3rd line (send(x)) is giving me problems. Seems right to me, but doesn't work. x is the car and name of the columns in Power. Any tips?
<% #cars.each do |x| %>
<% #power = Power.find_by_user_id(#user) %>
<% #power.send(x) = 0 %>
<% #power.save %>
<% end %>
Assuming #cars contains column names of Power, you need to send the setter method (i.e. with an = at the end). You also need to ensure you're passing a symbol to send.
#cars.each do |x|
#power = Power.find_by_user_id(#user)
#power.send(:"#{x}=", 0)
#power.save
end
There's also not an obvious reason why you need to set or save #power in the loop, so it might be better as:
#power = Power.find_by_user_id(#user)
#cars.each do |x|
#power.send(:"#{x}=", 0)
end
#power.save

Resources