In a rails view, how can I send output to view besides <%= %>? - ruby-on-rails

Short version:
It seems weird to me to have rails code like, say,
<% if #list.empty
%><%= val %><%
end %>
Is there some way to do something like this?
<% if #list.empty
some_display_function_i_wish_existed val
end %>
Long version:
I have a model, tweet.rb, that overrides to_s. The to_s works fine.
I have a view that needs to output to_s for each tweet in #meme.tweets .
I've observed the following:
<% #meme.tweets.each do |tweet|
tweet
end %>
Result: no output
<% #meme.tweets.each do |tweet|
puts tweet # or tweet.to_s does the same thing
end %>
...Result: no output
<%= #meme.tweets.each do |tweet|
tweet
end %>
...Result: output is entire inspection of each tweet, not to_s
<%= #meme.tweets.each do |tweet|
puts tweet # or tweet.to_s does the same thing
end %>
...Result: output is entire inspection of each tweet, not to_s
<% #meme.tweets.each do |tweet| %>
<%= tweet %>
<% end %>
...Result: works as intended (outputs result of to_s for each tweet). So does:
<%= #meme.tweets.collect do |tweet|
tweet.to_s
end %>
...Result: works as intended.
I come from a PHP background, and don't really understand the rules here.
I know I can do it the way I did in the last example.
But could someone explain why none of the other examples work as I intend?
It seems to me that the rules APPEAR to be:
1) <%= something %> will take that thing, call to_s on it, which will default to inspect if not overridden.
2) <% something %> will execute something
Is there a way to use 2) <% %> to send output to the view?
Or is it against the rules to have <% %> tags that span multiple lines of ruby code at all?

<%= code %> will print to the the output the result of the inner code. <% %> won't print anything, it just evaluates the inner code.
That's why the first example doesn't work. On the second example you expect the puts to print the tweets, but puts doesn't print on the same buffer... (you'll see the tweets printed on the rails console instead).
On 3rd and 4th example you are printing the collection as an object (#meme.tweets.each returns an Enumerable and ERb call #to_s on that) and not the code inside the block.
The 5th form is correct. That's what you'll normally do.
The 6th form is in some way correct too. There you are iterating a collection, calling #to_s on each element and then collecting them on a new array, that gets printed to the output (but you are printing an array of strings, not just one big string).
you can get a similar result with #join. (It returns a string created by converting each element of the array to a string)
<%= #meme.tweets.join %>

<% %> are used when you do not want the Ruby code you're executing to output anything. The <%= %> tags are used when you want to output something. This is why your example using <%= %> and tweet.to_s works as intended.
If you don't specify which attribute you want to output, then yes, puts will display the whole object. If for example, you had a message attribute on your tweet object, writing tweet.message (inside of a <%= %>, of course) would output just the message attribute of that tweet.

The direct answer is the concat function, eg:
Hi, my name is <% concat("Shelvacu") %>.
which is the same as
Hi, my name is <%= "Shelvacu" %>.
Which both output Hi, my name is Shelvacu.
Think of it like this: An erb template is parsed, transformed into valid ruby code, and then that ruby code is run*. Everything that is not inside <% ... %> is converted to concat("..."), <% statement %> is converted to statement, and <%= statement %> is converted to concat(statement.to_s).
So when ERB sees
1 + 2 = <%= 1 + 2 %>
<% puts "hello" %>
<% #meme.tweets.each do |tweet| %>
<%= tweet %>
<% end %>
that code is then translated to*
concat("1 + 2 = ")
concat((1 + 2).to_s)
concat("\n\n")
puts "hello"
concat("\n\n")
#meme.tweets.each do |tweet|
concat(tweet.to_s)
end
* This is an oversimplification, ERB does much more so that errors point the right line, statements don't merge with eachother in unexpected ways, and I didn't even mention <%- ... %>. However, this should be a decent mental model for understanding whats happening when you write code in ERB.

Related

Rails different output if block is given inline or over multiple lines

I'm having trouble finding out what I did wrong or how to achieve the same result.
What I'm trying to do is to print the array #attributes in a rails view.
This is not working:
<% #attributes.each do |element| %>
<%= puts element.to_s %>
<% end %>
But this is:
<%= #attributes.each { |element| puts element.to_s }%>
I've also played around with putting everything in the first statement in <%= %> without any success.
Aren't those two statements exactly the same?
Also, if you could help me out - how would you iterate over the array and insert a new line after each item?
Thanks in advance!
Alex
puts does not actually output to the ERB buffer. It outputs to STDOUT and returns nil. If you want to iterate through the records and output you would do it by:
<% #attributes.each do |element| %>
<%= element.to_s %>
<% end %>
The <%= %> ERB tags output the return value of the expression into the buffer. If you wanted to do this with a non-printing ERB expression you would need to use concat:
<% #attributes.each { |element| concat element.to_s } %>
Aren't those two statements exactly the same?
No. The output is actually the same as:
<% #attributes.each do |element| %>
<%= nil %>
<% end %>
And
<%= #attributes %>
Rails uses the ERB templates to render the views or say generate html documents for the browsers amongst others.
ERBcopies the text portions of the template directly to the generated document, and only processes code that is identified by markers. There are mostly two types of markers <% %> and <%= %>.
A tag with an equals sign indicates that the enclosed code is an expression and that the renderer should substitute the code element with the result of the code (as a string) when it renders the template.
Tags without the equals sign denote that the enclosed code is a scriptlet. Each scriptlet is caught and executed, and the final result of the code is then injected into the output at the point of the scriptlet.
<% #attributes.each do |element| %>
<%= puts element.to_s %>
<% end %>
With your example above you're telling the renderer to put whatever is the result of the expression in the second line, which is the output of the element.
Whereas here <%= #attributes.each { |element| puts element.to_s }%> you are asking rendered to put the #attributes object/variable along with the individual output of whatever is inside in #attributes variable which explains the difference in your output results.
PS you can avoid both puts and to_s from <%= puts element.to_s %> because whatever is inside <%= %> gets to the HTML document as a string itself.

How to return ActiveRecord Association Proxy on ERB

so I have a standard has_many through association in my models, very similar to the question here: Loop through ActiveRecord::Associations::CollectionProxy with each
I used the advice in that problem but I think I am having some trouble getting it through on my ERB file so that it shows up in my app. At the moment I have the following:
<%= #memberships.map do |a| %>
<%=a.name%>
<% end %>
In this scenario, the membership model is the one through which users and organizations have many though (#memberships = #user.organizations). So the #memberships.class returns
ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Organization
on the rails console. So the moment, in the browser the code returns on a page where the user is in two orgs:
orgone orgtwo["\n", "\n"]
I just don't know how to manipulate the proxy classes to return what I want. Thanks!
UPDATE:
I figured it out, I had to remove the = at the top of the block, and I added some styling with a comma:
<% #memberships.map do |a| %>
<h3><%=a.name %> <%= ", " unless a == #memberships.last %></h3>
<% end %>
If you want to print the name of each membership, what you want is
<% #memberships.each do |membership| %>
<%= membership.name %>
<% end -%>
The <% prefix in ERB executes code without appending the results to the output buffer, while the <%= prefix outputs the string representation of the result of the expression. Since each returns an enumerator, a <%= will return the string representation of the enumerator which is something like #<Enumerator:0xDEADBEEF.

Ruby How to display message if include? statement is true or false

I'm very new to Ruby and am attempting to display one of two messages based on whether certain words are included in an array. My current controller contains the following:
#cookie = ["gluten", "sugar", "dairy", "chocolate"]
And my view contains this:
<%= #cookie.include?"gluten" %>
The above returns 'true' and prints on the page just fine. However, nothing gets printed on the page when trying either of the following methods. The page renders fine with no errors, but no messages:
<%= puts "Sorry" if #cookie.include?"gluten" %>
and
<%=
if #cookie.include?("gluten")
puts "Sorry, you cannot eat this."
else
puts "You have the greenlight."
end
%>
I'm hoping that I'm creating a very simple mistake in syntax or am misunderstanding the usage of the include? function.
looking at the ruby it appears to be sound, http://rubyfiddle.com/riddles/d6798.
Must be rails error so try
<% if #cookie.include?("gluten") %>
<%= "Sorry, you cannot eat this." %>
<% else %>
<%= "You have the greenlight." %>
<% end %>
If you want it all in one erb statement, you would do something like this:
Don't use "puts". The "<%=" is already doing a 'to_s' and will output the value to the response body. You may have seen the results show up in your logs if you used 'puts'.
Also - for erb, the <% ... %> syntax, that is for logic, often an 'each' or 'if' state, the <%= %> is for writing to the screen. Most of the time it is the attribute of a ruby object like <%= user.name %>

Why is Rails' ERB rendering output from this template code?

I'm using Rails 3.0.3, and the following template (with a .html.erb extension):
<% "one"; "two"; capture do %>
Three
<% end %>
Is rendering as:
one
Why is this? It doesn't seem like it should render anything, since I didn't use <%=
EDIT
Since there seems to be some confusion, here is a reproduction that more closely resembles the actual template code that I'm debugging:
<% my_string = "" %>
<% my_string << capture do %>
Hello
<% end %>
<%= my_string %>
This is rendering as:
Hello Hello
Because for some reason, the captured output is being appended to my_string AND being rendered, instead of just the former.
You're using the rails capture helper but your syntax is wrong. I don't know why it's printing out one. In rails 3.4 it doesn't print out anything.
Here's the right way to use it
<% #number = capture do %>
three
<% end %>
this is some html and here is my <%= #number %>
The html that will be rendered is
this is some html and here is my three
Since your syntax is wrong I wouldn't worry about why "one" is showing up. Instead I'd focus more on using the capture helper correctly.
Edit:
Your second (edited) example is not the same as your first one. Here it is with line numbers and a slight change to the last line so you can see what's going on.
1. <% my_string = "" %>
2. <% my_string << capture do %>
3. Hello
4. <% end %>
5. before <%= my_string %> after
The result is Hello before Hello after. So line 3 is being rendered, then line 5 is being rendered with my_string containing the value Hello.
If you change it to this
<% my_string = "" %>
<% my_string = capture do %> <!-- changed << to = -->
Hello
<% end %>
before <%= my_string %> after
Then the result is before Hello after.
So what does this all mean? When you use << it's screwing up the capture method and it's rendering stuff that's inside the capture block even though normally you don't expect it to.
Basically, you can't do what you're trying to do here, at least not with your current syntax.

.find() returns hash-symbols!

I have this in one of my /views/ files:
<%= Result.find(:all) %>
Result is a model. This works fine in the console but it returns ['#,'#] in the view. It has recognised that I have two results but its not displaying the results. Any ideas why?
It's not a hash that is being returned, it is the concatenated string representation you are seeing.
<%= %> is the same as puts in the console. Example:
> puts User.all
#<User:0x00000102f98550>
...
If you want to see all the attributes you need to use inspect. Example:
> puts User.all.inspect
[#<User id: 2, email: "ga...
So:
<%= Result.find(:all).inspect %>
Still not going to be pretty output though, I guess you are doing this for debugging.
Or if you want to watch each of all the Results you just should do
<% Result.find(:all) do |result| %>
<%= result.your_result_attribute %>
<% end %>
Assuming you are using Rails < 3
The reason why you are getting a # is because the next character is a <, your browser is
interpreting that as a HTML element as such if you want to quickly see what that is, wrap it in a h()
i.e.
<%= h(Result.find(:all).inspect) %>
Use or debugger to debug or logger.debug to output it in your development.log.
What you are doing here is Result.find(:all).to_s because <%= %> will do a .to_s
To debug this properly:
<% logger.debug "Result.find(:all): #{Result.find(:all).inspect}" %>

Resources