Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render output of multiple expressions in one ERB block

I have a helper that looks like this:

if current_user.find_voted_items(vote_scope: :inspired).include?(post)
   link_to vote_inspired_post_path(post, vote_scope: :inspired), method: :post, data: { confirm: 'Are you sure this post Inspires you?' }, class: "btn btn-default" do
    "<i class='fa fa-lightbulb-o'></i> <br />Inspired".html_safe
   end
   link_to vote_happy_post_path(post, vote_scope: :happy), method: :post, data: { confirm: 'Are you sure this post makes you happy?' }, class: "btn btn-success" do
    "<i class='fa fa-smile-o'></i> <br />Happy".html_safe
   end
   link_to vote_disappointed_post_path(post, vote_scope: :disappointed), method: :post, data: { confirm: 'Are you sure this post disappointed you?' }, class: "btn btn-info" do
    "<i class='fa fa-meh-o'></i> <br />Disappointed".html_safe
   end
   link_to vote_upset_post_path(post, vote_scope: :upset), method: :post, data: { confirm: 'Are you sure this post upsets you?' }, class: "btn btn-inverse" do
    "<i class='fa fa-frown-o'></i> <br />Upset".html_safe
   end
end

I need all the links and their nested <i> tags to be rendered - but for some reason, this version is just rendering the last line.

All of that is inside a method called show_vote_buttons(post), that is being called like this in the view: <%= show_vote_buttons(@post) %>

What's the best way to tackle this?

like image 724
marcamillion Avatar asked Jun 28 '15 05:06

marcamillion


2 Answers

Basically, the reason behind this is that <%= %> renders the output of show_vote_buttons method. This method doesn't explicitly return anything, so the last evaluated expression is returned, in your case, the last link_to output.

In a general case, if you have not used a helper method and just pasted it's body instead with multiple link_to calls, you would get the same behavior. The reason is similar: <%= %> does not render each link_to, it executes code inside <%= %> and then outputs the result of last evaluated expression.

I see two different approaches to change the output:

  1. Helper method: concatenate the output of all evaluated expressions and print as one string:
    1.1 using << and parenthesis () around each link_to;
    1.2 creating a string with double quotes " and interpolating each link_to output with #{} in it;
    1.3 using concat;
  2. Partial views: build a separate view from your existing helper method and use <%= %> to output each link_to.

P.S. After testing all four methods I've come to a conclusion (here comes a personal opinion) that the second method is more preferable, at least because it keeps rendering in the views and avoids concatenation that can look messy. Similar approach is used, for example, in the Devise gem, where all shared links are located in the app/views/devise/shared/_links.html.erb partial.

like image 163
potashin Avatar answered Nov 14 '22 23:11

potashin


but for some reason, this version is just rendering the last line.

That reason is because in Ruby, if a method doesn't have an explicit return, then the returned value of a method is the value of the last line that got executed before a method exited. If you want to return multiple values from a method, use the return keyword and comma-separate your values.

#will return an array [1,2,3]
def some_method
 return 1,2,3
end

Also, I do agree with the other answers that your code should be more DRY, but I was simply trying to clarify your original question.

like image 32
Adib Saad Avatar answered Nov 14 '22 23:11

Adib Saad