Dissecting an ERB to HAML conversion example - ruby-on-rails

Directly rom the HAML tutorial:
<div class='item' id='item<%= item.id %>'>
<%= item.body %>
</div>
and the answer is
.item{:id => "item#{item.id}"}= item.body
I understood the reason for first .item, Ok it is a class so we declare it that way.
I also understood the hash, Ok when we have attributes we create a hash for it.
The part I couldn't understand how it is converted is "item#{item.id}"
Shouldn't be some sort of "=" sign somewhere? because it was saying when we want to calculate Ruby code use that "=" ?

{:id => "item#{item.id}"} is evaluated as hash in ruby code by Haml, so you don't need =

Related

Conditionally creating a hidden attribute in Slim with Ruby on Rails

I'm trying to get Slim to generate the following HTML if a CONDITION is true:
<div id="start_button" hidden="hidden">
I have tried various methods, like the obvious:
#start_button #{('hidden="hidden"' if CONDITION?)}
= link_to 'Get Started', ...etc...
but that generates:
<div id="start_button">hidden="hidden"
= link_to 'Get Started',..etc...
I know how to do it when setting an attribute like class etc. to something, but because it has got to be all or nothing with "hidden", it's causing me issues.
I've been down quite a few rabbit holes this evening, so any help appreciated!
This is stated in the docs:
Ruby attributes
Write the ruby code directly after the =. If the code contains spaces
you have to wrap the code into parentheses (...). You can also
directly write hashes {...} and arrays [...].
So, anything that's inside () is evaluated as Ruby code, if the statement is evaluated to false, it's somehow "skipped", otherwise it does what's stated in the true branch.
#start_button hidden=('hidden' if true)
<div hidden="hidden" id="start_button"></div>
#start_button hidden=('hidden' if false)
<div id="start_button"></div>

How to pre-populate a text-type input field in html via erb/ruby on rails?

I'm trying to get the following line to work in my Ruby on Rails project's erb.html file:
Student City:<input type="text" name="student[city]" value = <%= #student.city %>>
(This whole thing is inside of a form tag)
Everything works fine unless I give value a multi-word value, then it'll cut off everything after the space in the string.
To be specific, if student.city == "San Francisco", my page loads a text field with "San". I've tried changing it to different data types and manipulating the string and it still does the same thing. (Interestingly, trying to print the result after splitting the string into an array will display
["San",
Is this a known bug? Any ideas for a work around? If this is an actual bug with erb, how do I submit a bug report?
I wonder why you don't use Ruby on Rails' form helpers?
Something like:
<%= form_for #student do |f| %>
Student city: <%= f.text_field :city %>
# ...
<% end %>
Read more about form helpers in the Rails Guides.
You need to enclose them with double quotes:
Student City:<input type="text" name="student[city]" value="<%= #student.city %>" >

Is there a way of just having one pair of <% %> in ruby on rails [duplicate]

Sometimes it's more convenient to print in <%%>. How to do it in Rails?
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-concat
Should be what you are looking for.
E.g. the following statement using concat:
<% concat "Output" %>
is equivalent to:
<%= "Output" %>
In ERB:
The <% %> signify that there is Ruby code here to be interpreted.
The <%= %> says output the ruby code, ie display/print the result.
So it seems you need to use the extra = sign if you want to output in a standard ERB file.
Otherwise, you could look at alternatives to ERB which require less syntax,.. maybe try something like HAML. http://haml-lang.com/tutorial.html
Example:
# ERB
<strong><%= item.title %></strong>
# HAML
%strong= item.title
Is that more convenient?
erb has two method to evaluate inline ruby expressions. The <% which evaluates the expression and the <%= which evaluates and prints. There is no global object to print to within the binding context.
As mentioned by Omar, there is a concat method, which is part of ActionView. This will do what you want.
Unlike a scripting language escape, there is no default output for erb. Since erb is simply a function, and given a template and binding will return a variable, it returns the values of text and functions recursively.
There is hot debate as to how much logic should be allowed in a view, but as little as possible is what most people aim for. If you are putting more code than text in the view, you may want to consider refactoring your code.

Variable + HTML to Button + Ruby on Rails views

I am having a an issue.
<%= link_to "<button>Add</button>".html_safe, new_admin_course_path, :id=>"open-contacts-dialog-btn", :class=>"inbox-sf-add-btn tip" %>
What if I want to add a ruby variable and some normal text the button? e.g. $25,- (where the $ and ,- are fixed and the 25 variable...I am quite new to this...sorry if this is too easy, but struggling. I tried a lot of options and googled for long time.
The correct helper you want for this is button_to.
To use a variable in the button text is defined as string iterpolation. In your example it could be something like:
<%= button_to "$#{cost}", new_admin_course_path %>
Check out the button_to api reference for more options.
you could do like
amount = 25 #amount is the ruby variable
<%= link_to "<button>Add $#{amount}</button>".html_safe, new_admin_course_path, :id=>"open-contacts-dialog-btn", :class=>"inbox-sf-add-btn tip" %>
and I personally dont add <button></button> to the link and I rather use CSS to get the look and feel
Put your link inside a <button></button> tag. It'll be more readable.
And use variables interpolation in double-quoted strings to insert variable's value into string (the #{#variable_name} part)
<button>
<%= link_to "$#{variable_name}", new_admin_course_path, :id=>"open-contacts-dialog-btn", :class=>"inbox-sf-add-btn tip" %>
</button>

Include ERB delimiters inside of a string in an ERB block

I am working on a style guide which displays the code, as well as the output. It is currently structured so that the code only needs to be described once, and is displayed in both its raw and interpreted versions, like so:
<% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
#{ image_tag 'image.png' }
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
<%= raw code %>
<%= content_tag :pre, code, class: "prettyprint linenums" %>
This is great, and fairly easy to maintain. The problem comes in with the rails helpers, like image_tag in the above example. The view example correctly displays an image in a div, and the code example displays the relevant HTML. In this case, the relevant HTML includes an anchor tag - the results of the image_tag method, not the call itself.
I would prefer the code examples to display the helper methods, rather that their results. I am able to make this work by specifying the example code in a file, and either rendering or reading the file. I would prefer to make this work by specifying the code in a variable, as above, but I can't seem to get an ERB delimiter to work inside of a string inside of an erb block. Even the simplest case of <% foo = '<%= bar %>' %> doesn't work at all. I've tried playing with the syntax (<%% %%> and % % for example), using details from the official documentation, without much success.
The only information I could find on the matter is here, using <%= "<" + "%=" %> link_to <%= image.css_tag.humanize %> <%= "%" + ">" %> %>, which does not work in this use case (if at all).
So, is there a way to specify a string that contains a ERB end-delimiter (%>) in an ERB string, or am I stuck using the slightly clunkier file-read method? Thanks!
Edit:
What I would like to end up with is a working version of this:
<%# Idealized code - does not work %>
<% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
<% image_tag 'image.png' %>
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
So that <%= raw code %> would (continue to) output:
<div>
<img src="/images/image.png" alt="Image" />
</div>
And <%= content_tag :pre, code, class: "prettyprint linenums" %> would output:
<pre class="prettyprint linenums">
<div>
<% image_tag 'image.png' %>
</div>
</pre>
Instead of what it currently does when using a variable, which is:
<pre class="prettyprint linenums">
<div>
<img src="/images/image.png" alt="Image" />
</div>
</pre>
I want users to be able to copy the code example and paste it into a new view, without having to translate HTML back into the helpers that produce them. I think what I basically need is an alternative ERB delimiter, in the same way that ' and " (or even %q{}) vary for strings. It seems that even though the final ERB delimiter is occurring inside of a string, it is being actually processed as the end of the block. The simplest case of <% foo = '<%= bar %>' %> demonstrates somewhat what I want to accomplish. In a generator, you might use <% foo = '<%%= bar %>' %> (or something similar), to tell it not to process as ERB right then and there. This all works fine when reading from a file, or even in a pure rb file (like a helper), but it makes the most sense to put it in the view, in this case, as it is intended to be easily manipulated by our designers.
If I'm understanding you right, your real problem is that heredocs behave like double quotes as far as interpolation is concerned. So all you need is a quoting mechanism that behaves like single quotes. Ruby has lots of string quoting mechanisms, in particular we have %q{...}:
<% code = %q{
<div>
#{ image_tag 'image.png' }
</div>
} %>
You can use other delimiters if you'd like: %q|...|, %q(...), etc. There's still a change of course but at least you don't have to worry about interpolation problems.
If you really want to use a heredoc, you can specify the heredoc terminator with quotes and the corresponding quoting style will apply to the content:
<% code = <<'PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR'
<div>
#{ image_tag 'image.png' }
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%>
The single quotes in <<'PLACE...' specify that single quoting rules (i.e. no interpolation) apply to the heredoc's content.
Of course none of that stuff will work with embedded ERB like this:
<% code = %q{
<div>
<% ... %>
</div>
} %>
because the ERB parser will see the first %> as the closing delimiter for the outer <% code... part. Fear not, I think I have a plan that will work without involving gross hacks or too much work.
Some preliminaries:
Rails uses Erubis for ERB processing.
Erubis allows you to change the delimiters with the :pattern option to its constructor.
Rails uses Tilt and Sprockets to handle the template processing pipeline, these allow you to make the right things happen to pancakes.js.coffee.erb in the right order.
Using the above you can add your own template format that is ERB with a different delimiter and you can have Rails use this new format to handle your "special" sections before the normal ERB processing can make a mess of things.
First you need to hook up Tilt. If you have a look at lib/tilt/erb.rb in your Tilt installation, you'll see the Erubis stuff in Tilt::ErubisTemplate at the bottom. You should be able to subclass Tilt::ErubisTemplate and provide a prepare override that adds, say, a :pattern => '<!--% %-->' option and punts to the superclass. Then register this with Tilt and Sprockets in a Rails initializer with something like this:
Tilt.register(Your::Template::Subclass, 'klerb') # "kl" for "kludge" :)
Rails.application.assets.register_engine('.klerb', Your::Template::Subclass)
Now your application should be able to handle .klerb files with <!--% ... %--> as the template delimiters. And you can also chain your klerb with erb using names like pancakes.html.erb.klerb and the file will go through klerb before the ERB; this means that templates like this (in a file called whatever.html.erb.klerb):
<!--% code = <<PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
<div>
<% image_tag 'image.png' %>
</div>
PLACE_THE_EXAMPLE_CODE_BETWEEN_THESE_TWO_LINES_EXACTLY_AS_YOU_WANT_IT_TO_APPEAR
%-->
<!--%= "code = escape_the_erb_as_needed(%q{#{code}})" %-->
<% do_normal_erb_stuff %>
will do The Right Thing.
You'd need a helper to implement the escape_the_erb_as_needed functionality of course; a little experimentation should help you sort out what needs to be escape and in what way.
All that might look a bit complicated but it is really pretty straight forward. I've added custom template processing steps using Tilt and Sprockets and it turned out to be pretty simple in the end; figuring out which simple things to do took some work but I've already done that work for you:
Tilt::Template subclass, you get this by piggy backing on Tilt::ErubisTemplate.
Register with Tilt by calling Tilt.register.
Register with Sprockets by calling Rails.application.assets.register_engine.
...
Profit.

Resources