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.
Related
I have something like:
<%= "<p class='...'>#{product.value}</p>".html_safe if product.value %>
So I want to show the value wrapped in some html if it exists. Problem is that value is a method that requires some calculations and the way above for every product value is calculated two times which doubles my page loading time.
Any way to optimize this?
For readability reasons I would be very explicit:
<% if (calculated_value = product.value) %>
<p class='...'><%= calculated_value %></p>
<& end %>
I think the following should work:
<%= product.value.then { |v| content_tag(:p, v, class: '...') if v } %>
The value method is only called once on the product object. After that, it is passed to a block then that will define what is the result of the overall expression. Without calling again the value method, inside the block we determine what is the value that should be returned (if any).
Note: The generation of the HTML object has been replaced by an invocation of the content_tag helper method.
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 ').
Let's say I've got the variable #var. Usually I would use <%= #var %> to write it into the view. Now I want to call a module method from within my view which internally decides to write the content of #var or not.
Inside the module I can't use <%= %>. How can I print the content of #var from within the module? The method would be called like this: <% my_method %>. Thanks
Update
Thanks for the answers so far. Maybe I should say more about my initial problem to be more clear. Sorry if I wasn't clear enough.
At first I used the <%= %> tag like this:
def print_if_present(var)
var ? var : ""
end
<%= print_if_present var %>
But then, when the var was nil, I got "" as output, which took space in the view. How can I prevent this behavior?
I assume that your module is actualy the view helper. If is that so, simply return var.
def my_method
if my_condition
#var
else # else clause is optional
#other_var
end
end
Note that the else clause is optional. If you want to write something or nothing, you can simply use the if. This is so because if the if is not executed and there is no else, it will return nil, that will be casted to an empty string in your template. Just to ilustrate,
if true
1
end
=> 1 #return if last value
if false
1
end
=> nil # return nil because there is no else block
Since you still want to print the return of your method on your template, you need to keep the equal sign:
<%= my_method %>
The best way to do this is to have your method return the string and use <%= ... %> as in fotanus’ answer, but in Rails if you really need to write output directly from a helper you could use the concat method:
The preferred method of outputting text in your views is to use the <%= “text” %> eRuby syntax. The regular puts and print methods do not operate as expected in an eRuby code block. If you absolutely must output text within a non-output code block (i.e., <% %>), you can use the concat method.
So you can define a helper like this:
def my_method
if some_condition
concat "Something or other"
else
concat "Something else"
end
end
And then use it in a non-output block:
<% my_method %>
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 | %>
I have a problem trying to make a list from a acts_as_taggable_on tag_list
I have tag list array, and I want to list it so im trying this:
<%= proyects.tag_list.each do |tagsx| %>
* <%= tagsx %> <br>
<% end %>
And I get the list im looking for, but also the whole array again...
When it renders, looks like this..
* AJAX
* Rails
* Heroku
* Prototype
AJAX, Rails, Heroku, Prototype
Any ideas on getting rid of the last line?
Or do you guys know a more efficient way of achieving this?
Thanks in advance.
Change this:
<%= proyects.tag_list.each do |tagsx| %>
to this:
<% proyects.tag_list.each do |tagsx| %>
You don't want to output the return value of the .each call, just the elements of the array. Calling Array#each with a block returns the array (as you are):
each {|item| block } → ary
each → an_enumerator
Calls block once for each element in self, passing that element as a parameter.
If no block is given, an enumerator is returned instead.
and that's were the comma delimited list is coming from.
because you have a typo in your code :-)
<%- proyects.tag_list.each do |tagsx| %>
* <%= tagsx %> <br>
<% end %>
see the difference?
no '=' after the first % sign
%= means that the result of a Ruby expression is returned to the view
%- means that the Ruby expression is evaluated, but no result is returned
The code in your question gets "proyects.tag_list" , executes the loop, during which it prints out the individual tags, and then returns the whole array to the view because of the '='