Retrieve data using for loop in Ruby - 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 %>

Related

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

Rails- Index in form_for field names

I have a form that I am trying to build to edit multiple records. It's complicated, doesn't map straight to the database, and there can be any number of records. I have the code written so all of the data is passed to the view as a hash. Like this:
#formdata = {"datafield_1"=>"value_1", "datafield_2"=>"value_2"}
What I want to do is to create something like:
f.textfield :datafield_1
f.textfield :datafield_2
f.textfield :datafield_3
etc. etc. etc.
But I don't know how to pass the index of my for loop into the variable name. In short, how do I do :datafield_i where i is my index?
<% %w(1 2 3).each do |i| %>
<%= f.textfield(:"datafield_#{i}") -%>
<% end %>
or
<% #formdata.keys.each do |datafield| %>
<%= f.textfield(datafield.to_sym) -%>
<% end %>

In a Ruby each block, how do I do something to the last record in the array within the block?

Say I have a block like this:
<% #help_sections.each do |section| %>
<li><%= section.name %></li>
<% end %>
But on the last record returned, I want to do something else, e.g. applying a class to the li that's there:
<li class="last"><%= section.name %></li>
How do I do that in the most DRY way?
Thanks.
Edit1:
I imagine I would simply use an if statement and the last ruby method, but not sure how to do that within the block? I know that if I just wanted the last element in that array, I could just do #help_sections.last, but that doesn't make sense within the confines of a Ruby block.
The most DRY way is to use CSS instead. Instead of e.g. this:
li.last { color: red; }
..and then cluttering up your markup with an extra CSS class, just use the :last-child pseudoselector, i.e.:
li:last-child { color: red; }
Then you don't have to change anything in your view. This is supported in all modern browsers including IE9.
Try each_with_index:
<% #help_sections.each do |section, index| %>
<li <%= "class='last'" if index == (#help_sections.length-1) %>><%= section.name %></li>
<% end %>
DRY is a good idea in general, but don't kill yourself to keep from repeating a li.
<% #help_sections[0...-1].each do |section| %>
<li><%= section.name %></li>
<% end %>
<li class="last"><%= #help_sections.last.name %></li>
You could either do something like
<% #help_sections.count.times do |i| %>
<%= #help_sections[i].name %>
<%= do_something if #help_sections.count == i - 1 %>
<% end %>
This old answer might help (Tell the end of a .each loop in ruby). Basically, you can use:
<% #help_sections.each_with_index do |section, index| %>
<% if index == #help_sections.size - 1 %>
<li class="last">
<% else %>
<li>
<% end %>
<%= section.name %></li>
<% end %>
If you use each_with_index instead of plain each, the block will also be passed the index of the current element within the collection. You can then compare that to #help_sections.length.
E.g.
<% #help_sections.each_with_index do |section, i| %>
<li<% concat " class='last'" if i == #help_sections.length - 1 %>><%= section.name %></li>
<% end %>
In general cases not covered by smart CSS selectors, you can define a convenient helper method, which would provide each iterated element with its context within the collection. Like this one:
def each_with_context enum
length = enum.count
enum.each_with_index do |elem, i|
context = {
:first => i == 0,
:last => i == length - 1,
:even => i.even?,
:odd => i.odd?,
:middle => i == length / 2
}
yield elem, context
end
end
And then use it within HAML view like this:
-each_with_context(#help_sections) do |section, context|
%li{:class => context[:last] ? 'last' : nil}
=section.name

Resources