Rails - single line 'if' shorthand not working in views - html

I have this markup in my view file:
<ul class="nav navbar-nav navbar-right">
<li class="nav-item">Restaurants</li>
<li class="nav-item">Contact</li>
<li class="nav-item">Logout</li>
</ul>
To conditionally display the Logout link, I put the single line if
<li class="nav-item">Logout</li> <% if condition %>
This did not work and gave error.
The full if form is working normally
<% if condition %> <li class="nav-item">Logout</li> <% end %>
Any ideas why the shorthand does not work in views?

CASE 1:
<li class="nav-item">Logout</li> <% if condition %>
The html statement is executed and then the ruby code injection is encountered. The preceding HTML code is not syntactically related to the if condition
following it. If you were to change it into something like:
<% '<li class="nav-item">Logout</li>'.html_safe if condition %>
It would work as you are expecting it to. Here the html block is a part of the statements that need to be executed after the if condition has been evaluated to true
* html_safe is required to allow the block to be treated as an HTML block and not a string.
CASE 2:
The full if form is working normally
<% if condition %> <li class="nav-item">Logout</li> <% end %>
The if condition is encountered first, if it evaluates to false, all code between if and end is skipped and execution continues from the end of the block. Hence the HTML is not rendered.

Sure, that part before the if is not a Ruby expression. It has nothing to do with the if, so it expects the full form.
Anyway, this should work in pure Ruby but it's not so good, I know.
<%= content_tag(:li, class: 'nav-item') { link_to('Logout', your_path) } if condition -%>

Related

Is there a way to add HTML inside a Rails partial argument?

I have been trying to find something about embedding HTML code inside a partial argument for days but I have not found anything so I'm guessing it isn't possible. But it seems like it should be.
I have a static page in my Rails app which has a lot of sections and each section can have subsections. I could just make the entire page just plain HTML. But I didn't want to repeat the same formatting over and over in case I want to change classes or something else.
So I have the following _section.html.erb partial file:
<div class="row">
<h4><%= heading %></h4>
<% subsections.each do |section| %>
<% if section[:header] %>
<h5 class="primary-text"><%= section[:header] %></h5>
<% end %>
<p><%= section[:body] %>
<% end %>
</div>
That works fine. But what if I want to include a link to a page or an email inside one of the subsections? It doesn't work just by passing it in as part of the quotes text. It shows the actual HTML tags.
Is there a real way to do this or should I give up and just write plain HTML with repeated section formatting?
You mark your text as html_safe. For example:
<%= section[:header].html_safe %>
But I would suggest using sanitize method because of security resonons:
<%= sanitize section[:header] %>
Probably sometimes you will want to configure sanitize method. Here you can read how to do this:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
You can read more about security here:
http://guides.rubyonrails.org/security.html#cross-site-scripting-xss

How are elements in an eRubis document cloned throughout the page?

I have a simple eRubis (*.html.erb) document, and want to "copy" various elements throughout a page. Whenever I use simple Ruby statements like this:
<%= 3.times do %> ... <% end %> with multiple "times" statements within that to copy more elements returns either errors or horribly rendered elements. What is the best way to "copy" multiple elements throughout a eRubis page using Ruby statements?
One approach I use in RoR is content_for and yield. I store my element(s) in a content_for and then I litter yields around wherever I want that element:
<% content_for :some_elements do %>
<divs or whatever />
<and maybe some things too />
<%= even some more erb %>
<% end %>
<%= yield :some_elements %>
<%= yield :some_elements %>
<%= yield :some_elements %>
Those yields can go anywhere, you could even have the content_for in your layout file and put those yields in any view or partial as many times as you want.
If you want to simply mock up a list or something, times works perfectly well if you use it correctly:
<ul>
<% 10.times do |i| %>
<li id="item_#{i}">
content in item <%= i %>
</li>
<% end %>
</ul>
But of course the times approach requires that all the elements be in the same spot. That's the advantage of the content_for/yield way, you can place the yields where ever you want. You can even put a yield inside a times:
<% 10.times do |i| %>
<%= yield :some_elements %>
<% end %>
But that's just crazy. Anyway, have fun.

Old HTML added in production on Heroku with Rails 3.2.1

This is the code that I have for my posts/index.html.erb file:
<!--
Iterate over each post in list format
-->
<% #posts.each do |post| %>
<ul class="posts">
<!--
Link to article, display date created, show edit, delete links if logged in
-->
<li><%= link_to "#{post.title}".html_safe, post, id: "article" %></li>
<li id="date"> <%= post.created_at.strftime("%B %Y") %></li>
<% if logged_in? %>
<li>
<%= link_to 'Edit', "/editor" + post_path(post), id: "edit_delete", data: {save_url: mercury_update_post_path(post)} %>
<%= link_to 'Delete', post, id: "edit_delete", :method => :delete %>
</li>
<% end %>
</ul>
<% end %>
In my local development and production environments, the associated css stylesheet and html compiles and renders in the browser properly. BUT, when I deploy this code to heroku, it adds some old HTML that I had deleted earlier, as seen in the page source code:
<!--
Iterate over each post in list format
-->
<ul class="posts">
<!--
Link to article, display date created
-->
<li> <a href="/posts/5" id="article"><b>Endurance Exercise is Bad for your Health?</b>
<div><b><br></b></div></a> </li>
<li id="date"> February 2013 </li>
<!--
Show edit, delete links if logged in
-->
</ul>
see the <div><b><br></b></div> tags embedded within the link tag for the article "Endurance Exercise is Bad for your Health?" ... Anyone know why that is being put there when deployed to heroku on production?
This is your culprit. "#{post.title}".html_safe
One of the posts that you are displaying has html tags in its title. It's a bad idea to call .html_safe to anything entered by a user. You should escape that using h(post.title) or sanitize the string first for accepted tags. Look at the sanitize helper

Navigation menu in rails

I have my navigation menu in application.html and the menu has class="active" . That depends on the page the user is on. How can I dynamically figure out which item needs to have the class:
Here's how my top menu bar is:
<ul>
<li class="active">Home</li>
<li>Page1</li>
<li>Page2</li>
<li>Page3</li>
</ul>
One way would be to have an #active_page instance variable in the controllers, which you set on each action. You may also do this already with a title (#title maybe?), so perhaps you could use that instead. Then in the template:
<li class="<%= "active" if #active_page == "Home" %>">...</li>
The easiest (and possibly the most rudimentary) is to use current_page?. You can read up in the docs to see how it works. As I've experienced, it does not always produce what you want.
There is also a gem, navigasmic, which works pretty well if your needs get fairly complex.
There are a number of ways to accomplish what you are trying to do. Try out current_page? first and if you find yourself ripping your hair out, move on to something like navigasmic.
you can create a siple helper like this
def nav_link(name, url)
selected = url.all? { |key, value| params[key] == value }
link_to(name, url, :class => (selected ? "youarehere tabs" : "tabs"))
end
<div id="tabs" class="tabs2">
<%= nav_link %>
<%= nav_link %>
<%= nav_linl %>
</div>
then add the necessary css styles

How to keep style for HTML in Ruby/Rails?

I'm a beginner to Ruby/Rails, and just generated my first HTML programmatically - kind of exciting-- but when I viewed "page source" from the browser, my HTML had all these additional gaps and messed up the logical indentation:
This code in a View:
<% #states_array.each do |state| %>
<ul><%= state %></ul>
<% end %>
and this code in my application.html.erb layout:
Practice Header
<div class="text">
<%= yield %>
</div>
<div class="footer">
</div>
Produced this HTML when I viewed page source for that page:
<div class="header">
Practice Header
</div>
<div class="text">
<ul>California</ul>
<ul>Colorado</ul>
<ul>Florida</ul>
<ul>Georgia</ul>
<ul>New York</ul>
<ul>North Carolina</ul>
<ul>North Dakota</ul>
<ul>Oregon</ul>
</div>
<div class="footer">
</div>
only an extra space occurred after each row, and the logical indentation of where I put the <%= yield %> was lost. Thanks so much for your help in advance.
You can suppress the trailing newline by closing with a minus sign:
<% some.ruby.statement -%>
If the beauty of your markup really matters to you, look into Haml (http://haml-lang.com/).
<% #states_array.each do |state| %>
<ul><%= state %></ul>
<% end %>
Results in the string "\n<ul>state</ul>\n" for each state in the array. So the output is technically correct. You could use
<% #states_array.each do |state| %><ul><%= state %></ul>
<% end %>
But that's not as easy to read in your code. I've read there is a way to skip the trailing new lines but don't recall the exact method (Update: see #user156011's answer).
But the truth is - it doesn't really matter. HTML is for the browser - don't worry about how it looks. The only time you really need to pay attention is when two tags must exist one after the other without spacing to prevent browsers from injecting default whitespace - like in a series of tags sliced up from a larger image.
If you're going for markup readability - Haml has been nothing but a dream for me.
In development mode, it outputs gorgeous HTML that is properly indented.
It'll switch to "ugly mode" by default when your app is run in production mode, to save on server resources.
However, if you're new to Ruby/Rails, learning a new templating language may not be in your best interest. (Still, I'd argue that if you can learn ERb, you can easily pickup Haml in a day.)
If you're going to stick to ERb, you can use the <%- and -%> will respectively supress leading/trailing whitespace. Which may help in your quest for clean markup.
Best of luck :)
~Robbie
You should probably change it to something like:
<ul>
<% #states_array.each do |state| %>
<li><%= state %></li>
<% end %>
</ul>