Display Block Conditionally

I have seen a number of examples where HTML code is treated as a Ruby
block. For example, here is one taken from the Agile Rails book:

<% content_for( :sidebar) do %>
  <ul>
      <li>this text will be rendered</li>
      <li>and saved for later</li>
      <li>it may contain <%= "dynamic" %> stuff</li>
</ul>
<% end %>

I have no idea how this works. Can someone please give me a clue as
to how this works? Additionally (and this is what I am really trying
to do) I'm wondering if there isn't some way I could use this approach
to display a block of HTML code conditionally. Any ideas?

Thanks for any input.

          ... doug

I have seen a number of examples where HTML code is treated as a Ruby
block. For example, here is one taken from the Agile Rails book:

<% content_for( :sidebar) do %>
<ul>
     <li>this text will be rendered</li>
     <li>and saved for later</li>
     <li>it may contain <%= "dynamic" %> stuff</li>
</ul>
<% end %>

I have no idea how this works. Can someone please give me a clue as
to how this works? Additionally (and this is what I am really trying
to do) I'm wondering if there isn't some way I could use this approach
to display a block of HTML code conditionally. Any ideas?

Not sure what you mean by conditionally... if it's something server side you could just do:

<% if this_expression_evaluates_to_true %>
   put your html here
<% end %>

The way content_for works is to capture the result of the block (everything in b/n) and save it for later. You can get it back by doing

<%= yield :sidebar %>

-philip

I have seen a number of examples where HTML code is treated as a Ruby
block. For example, here is one taken from the Agile Rails book:

<% content_for( :sidebar) do %>
<ul>
<li>this text will be rendered</li>
<li>and saved for later</li>
<li>it may contain <%= "dynamic" %> stuff</li>
</ul>
<% end %>

I have no idea how this works. Can someone please give me a clue as
to how this works? Additionally (and this is what I am really trying
to do) I'm wondering if there isn't some way I could use this approach
to display a block of HTML code conditionally. Any ideas?

It captures the block and stashes it away for later. Don't you just
want

<% if something %>
html here
<% end %>

though ?

Fred

It might be worth your while working through some of the rails guides
at http://guides.rubyonrails.org/, particularly the Getting Started
guide. This should get you going with the fundamental operation of
Rails.

Good luck

Colin

Not sure what you mean by conditionally... if it's something server
side you could just do:

<% if this_expression_evaluates_to_true %>
   put your html here
<% end %>

That is exactly what I'm talking about and it gives me a great basis
for trying to articulate what is confusing me.

I am apparently under the mistaken impression that when we insert into
an HTML document Ruby code that is included within <% %> like this:

<% ruby code %>

the inserted Ruby code is run at the point where it is inserted into
the HTML document. When that Ruby code completes, any HTML code that
follows is sent to the requesting browser. The point is that at any
given time either Ruby code is being run or HTML is being sent to the
requesting browser. What your Ruby code does is interact with a
segment of HTML code so that that segment of HTML code is sent to the
browser conditionally. That just blows my mind. How are we able to
accomplish that? Or, is that just something that I should accept and
try not to think about too much? I would think that if we were going
to include content conditionally, that content would have to be within
the <% %> and quoted. My concern is that I am missing some very
important point about <% %> that, if I weren't missing it, my
understanding would be a whole lot better.

The way content_for works is to capture the result of the block
(everything in b/n) and save it for later.

Yes. I understand what content_for does. I was just using it to
provide an example of the type of thing that I was talking about.

Thanks to all for the input.

         ... doug

Not sure what you mean by conditionally... if it's something server
side you could just do:

<% if this_expression_evaluates_to_true %>
  put your html here
<% end %>

That is exactly what I'm talking about and it gives me a great basis
for trying to articulate what is confusing me.

I am apparently under the mistaken impression that when we insert into
an HTML document Ruby code that is included within <% %> like this:

<% ruby code %>

the inserted Ruby code is run at the point where it is inserted into
the HTML document. When that Ruby code completes, any HTML code that
follows is sent to the requesting browser. The point is that at any
given time either Ruby code is being run or HTML is being sent to the
requesting browser. What your Ruby code does is interact with a
segment of HTML code so that that segment of HTML code is sent to the
browser conditionally. That just blows my mind. How are we able to
accomplish that? Or, is that just something that I should accept and
try not to think about too much?

Being inquisitive about the code you are running is a good thing. If
you really want to know, every Ruby installation ships with erb.rb in
the /path/to/lib/ruby/1.x/ directory. But the shorter path to your
answer is that ERB scans your code for lines with <% and %> in them.
The code inside is evaluated using the eval method. If there is an
equal sign (<%=), then the results of the expression evaluation are
concatenated to the end of the output stream. Anything outside the <%
delimiters is treated as a string to be concatenated directly to the
end of the output stream. This is an oversimplification, but that
should give you an idea what makes things tick.

The key concept is that no output is generated and no expressions
evaluated until the moment a page is rendered. The Ruby doesn't so
much interact with the HTML code as to accept the HTML code as
arbitrary strings that are (according to normal Ruby control flow
statements) concatenated onto an output stream.

Thanks so much for your kind explanation. Unfortunately, it still
doesn't make sense to me.

The documentation for the ERB class tells us:

<% Ruby code -- inline with output %>
<%= Ruby expression -- replace with result %>

That makes perfect sense. The documentation even alludes to the
capability in question in an example; but, it really isn't discussed.
In discussing <% %>, the Agile Rails book makes the observation,
"Interestingly, this kind of processing can be intermixed with non-
ruby code." Then they give a minor example and launch into a
discussion dealing with extraneous new line characters.

Am I alone in thinking that this is a monumental capability that
deserves a better understanding?

Anyway, thanks very much for the response. I'm sorry that it didn't
quite bridge the gap for me. I guess that I either have a mental
block or am just super dense. Thanks again.

         ... doug

Have you tried working through the Getting Started guide at
http://guides.rubyonrails.org/ ? If not then doing that may help to
clarify things.

Colin

Ok, I oversimplified it. This discussion really belongs on the ruby-talk ML, but here is the longer explanation. Assuming you have the code:

require 'rubygems'
require 'erb'

template =<<EOD
This is plain text
And the time is <%= Time.now %>
<% if true %>
   it was true
<% else %>
   it wasn't true
<% end %>
EOD

puts ERB.new(template).result

Then after compiling it, ERB creates:

"_erbout = ''; _erbout.concat \"This is plain text\\n\"\n_erbout.concat \"And the time is \"; _erbout.concat(( Time.now ).to_s); _erbout.concat \"\\n\"\n if true ; _erbout.concat \"\\n\"\n_erbout.concat \" it was true\\n\"\n else ; _erbout.concat \"\\n\"\n_erbout.concat \" it wasn't true\\n\"\n end ; _erbout.concat \"\\n\"\n_erbout"

Without getting into the details of how ERB scans and tokenizes the text, the point I want to make is that what you thought was HTML is nothing more than a bunch of strings to ERB. These strings are passed to eval, which evaluates and runs them as Ruby code. So check it out. I just reformatted the code above:

"_erbout = ''
_erbout.concat \"This is plain text\\n\"\n_erbout.concat \"And the time is \"
_erbout.concat(( Time.now ).to_s)
_erbout.concat \"\\n\"\n
if true
   _erbout.concat \"\\n\"\n_erbout.concat \" it was true\\n\"\n
else
   _erbout.concat \"\\n\"\n_erbout.concat \" it wasn't true\\n\"\n
end
_erbout.concat \"\\n\"\n_erbout"

And you can see how the if and else affect what strings are output.

For a more in-depth example, just do what I did: Create the ERB, punch it into rdebug, and step through it. Ain't it cool to have source?

Steve

"_erbout = ''
_erbout.concat \"This is plain text\\n\"\n_erbout.concat \"And the
time is \"
_erbout.concat(( Time.now ).to_s)
_erbout.concat \"\\n\"\n
if true
   _erbout.concat \"\\n\"\n_erbout.concat \" it was true\\n\"\n
else
   _erbout.concat \"\\n\"\n_erbout.concat \" it wasn't true\\n\"\n
end
_erbout.concat \"\\n\"\n_erbout"

Thanks so much, Steve. I think that I get the essence of how it
works. It does not seem that erb directly translates an input
document into an output stream. Rather, it appears that erb produces
a Ruby program that, when run, produces the output stream. Lines of
the input document that consist wholly of text (i.e., they do not
contain any '<%' beginning markers or '%>' ending markers) are passed
as an argument to a method called erbout.concat which adds the line to
the output stream when the program is run. Thus, the intermediate
program contains a series of calls to erbout.concat (one for each text
line). Thus, if the input document contains no lines which include
beginning or ending markers, the intermediate program consists
exclusively of a series of calls to the erbout.concat method (one for
each line of input) with the relevant line passed as an argument to
the method. If such a program is run, it simply outputs the original
document.

Now, let's see what happens when <% %> and <%= >%> markers are
introduced into the document. First of all, any such content is
treated as being placed on a separate line. So, if we we had:

The quick brown <% fox %> jumped over the lazy dog.

That would be treated as being:

The quick brown
<% fox %>
jumped over the lazy dog

The 'The quick brown' and 'jumped over the lazy dog' are now just
plain lines of text and as such they are treated accordingly by each
being passed as an argument to a call to the erbout.concat method.
What do we do with <% fox %>? Pretty much nothing. We through away
the beginning and ending markers and leave simply 'fox'. 'fox' is now
a fragment of Ruby code which will be run along with the other lines
of code, e.g., calls to erbout.concat when the program is run.

That only leaves us with figuring out how content within <%= and %>
markers is treated. That's pretty easy. The enclosed content is
evaluated as a Ruby statement and the output is treated as a line of
text which is passed as an argument to a separate call to
erbout.concat.

I think that's basically it. I feel much better now. I welcome any
comments on my analysis.

Thanks to all who contributed.

          ... doug

P.S. Colin, I didn't mean to ignore you; but, I didn't really see
anything in the Getting Started Guide that would help me with this
issue. Thanks for the input though.

jumped over the lazy dog

steve

that's the first outline of erb I have seen. Either it doesn't get
discussed a lot, or it is discussed in places I don't visit. Anyway,
although I had a broad idea of what was going on under the bonnet, I
had never really seen a clear example of an erb template in action. I
use haml, and I have often wondered how it hooks into erb. With your
example, I am inspired to delve into that a bit when I get some spare
time.

Thanks
Tony

Tonypm wrote:

steve

that's the first outline of erb I have seen.

Glad to be of help.

Yes, thanks for that. I know intuitively how ERb works, but had never
looked at the internals in any detail.

[...]

I
use haml, and I have often wondered how it hooks into erb.

As far as I know, it doesn't (unless you use the :erb filter). It
is a
completely separate template handler, I think.

Haml has a separate engine and the code is very readable. Go to your
Gem directory or plugin directory and have a peek.

Doug,

I recall I went through a similar 'wow' experience, and it helped me
sort out how this was working when I realised I could think of <% and
%> in the reverse of the way they are normally presented.

By that I mean, insted of seeing a <% %> pair as bracketing ruby code
embedded in the middle of HTML, think of it as a %> <% pair bracketing
text in the middle of ruby code. (This needs a bit of mind-twisting at
first - not to mention odd details like an assumed %> at the beginning
of the document.) Then imagine the resulting patterns such as

    %>html text<%

as replaced by ruby code such as

   puts "html text"

and it is easy to see why the text is output conditionally when it
sits inside an 'if' statement.

(I am not suggesting that erb (or anything else) actually works this
way, but I found it helped me see what was going on. YMMV :wink: )

Having read subsequent posts, I would comment that I have also
discovered the joys of HAML and would not now use anything else.

Graeme