Conditional line spacing in ERb partials - ruby-on-rails

This is the code for an address partial I just wrote. People might put single line addresses in either street line, company name is optional, etc... It works exactly how I want it to, but I know that checking each variable twice is ugly and terrible.
<%= "#{a.name}" unless a.name.blank? %>
<% unless a.name.blank? %> <br> <% end %>
<%= "#{a.company_name}" unless a.company_name.blank? %>
<% unless a.company_name.blank? %> <br> <% end %>
<%= "#{a.street_1}" unless a.street_1.blank? %>
<% unless a.street_1.blank? %> <br> <% end %>
<%= "#{a.street_2}" unless a.street_2.blank? %>
<% unless a.street_2.blank? %> <br> <% end %>
<%= "#{a.city}, #{a.state} #{a.zip}" %>
So, my gratuitous use of unless aside, how should I be putting in a conditional line break?
Update:
As discussed below, it is dangerous to use .html_safe on user input. If you do use a helper method as suggested below, you must also sanitize all user input on the way into the database. I've rewritten the code above as:
<% unless a.name.blank? %>
<%= a.name %>
<br>
<% end %>
<% unless a.company_name.blank? %>
<%= a.company_name %>
<br>
<% end %>
<% unless a.street_1.blank? %>
<%= a.street_1 %>
<br>
<% end %>
<% unless a.street_2.blank? %>
<%= a.street_2 %>
<br>
<% end %>
<%= "#{a.city}, #{a.state}" %> <%= a.zip %>
The redundant checking was just me overcomplicating things. I'd strongly recommend against using .html_safe in a situation like this, since you create new problems for yourself: sanitizing the input, and remembering which fields are safe. Better to not override the sensible protection Rails provides.

There are many, many ways to go about cleaning it up, but a helper would be appropriate here:
module ApplicationHelper
def format_address(a)
top = [a.name, a.company_name, a.street_1, a.street_2]
top.reject! {|s| s.blank?} # remove null and empty values
"#{top.join('<br/>')}#{a.city}, #{a.state} #{a.zip}".html_safe
end
end
Then in your view:
<%= format_address(a) %>

Related

How to specify syntax error in Ruby on Rails

My controller is like this
def show
#receipt = Receipt.find(params[:id])
#hospitalizations=#receipt.hospitalizations
#outpatients=#receipt.outpatients
#surgeries=#receipt.surgeries
end
my show.html.erb is like this.
<h1>details of receiptid: <%= #receipt.id %></h1>
<% #hospitalizations.each do |hospitalization| %>
<p>hospitalization_id:<%= hospitalization.id %>hospitalization_start :<%= hospitalization.hospitalization_start %> hospitalization_end:<%= hospitalization.hospitalization_end %> </p>
<% #surgeries.each do |surgery| %>
<p>surgeryid:<%= surgery.id %> surgery_day :<%= surgery.surgery_day %> </p>
<% #outpatients.each do |outpatient| %>
<p>outpatientid:<%= outpatient.id %>outpatient_day :<%= outpatient.outpatient_day %> </p>
<% end %>
When I access it's page,some error like below was incurred. I tried to specify error location,but didn't work well.
It seems syntax error,where should end insert?
If someone has experienced same issues,please let me know.
Each of your each loop requires an <% end %> clause, you can't find the specific line since the error says it reached the end when it expected "end". Close all your loops like this:
<% #hospitalizations.each do |hospitalization| %>
<p>hospitalization_id:<%= hospitalization.id %>hospitalization_start :<%= hospitalization.hospitalization_start %> hospitalization_end:<%= hospitalization.hospitalization_end %> </p>
<% end %>

Dynamically displaying the column values

Here, I have 10 columns i.e., answer1, answer2, answer3, ..., answer10 in the table MgAnswer.
I have to check whether each column value is present or not. Only if it present,then I have to display it in the page.
Im giving column names dynamically within for loop
<% (1..10).each do |i| %>
<% if MgAnswer."answer#{i}".present? %>
<%= MgAnswer."answer#{i}" %>
<% end %>
<% end %>
Im ending up with Syntax error.
You can indeed dynamically invoke methods in ruby, but this is not the syntax. Instead do
<% (1..10).each do |i| %>
<% if MgAnswer.public_send("answer#{i}").present? %>
<%= MgAnswer.public_send("answer#{i}") %>
<% end %>
<% end %>
It should seem like the following:
<% (1..10).each do |i| %>
<%= MgAnswer.send("answer#{i}") %>
<% end %>
Since ruby can't evaluate line as MgAnswer."method". Also you can just skip if condition, because it will be evaluated to empty string "".

(not) displaying optional fields in rails

(Disclaimer: I'm a bloody rookie)
My model contains some optional values. It seems that they may not exist at all (==nil) or that they may exist but are empty. In both cases, I don't want to show anything in my view. Currently, I do it like this:
<% if #score.lyricist and not #score.lyricist.empty? %>
<p>
<strong>Lyricist:</strong>
<%= #score.lyricist %>
</p>
<% end %>
This seems awkward and repetitive. Is there a better way?
blank? method will check both nil and empty values
<% unless #score.lyricist.blank? %>
<p>
<strong>Lyricist:</strong>
<%= #score.lyricist %>
</p>
<% end %>
Documentation here
present? method is the opposite of blank? method.
<% if #score.lyricist.present? %>
<p>
<strong>Lyricist:</strong>
<%= #score.lyricist %>
</p>
<% end %>

How to add a line break with conditional operators

OK, stupid newbie question: how do you make a line break only when it's needed?
I'm creating a basic address listing and only want to include a line of an address if it isn't blank. How do I keep the blank line from printing? I've tried including the break and new line tags, and tried using puts and quotation marks of both varieties and escaping the slashes but can't seem to display the address correctly.
Is there a way to have each line of the address to print on its own line or simply omit the line if there is no info to put on it?
Here's the current version of the code:
<p><strong>Main Address</strong></p>
<p><%= if #vendor.address1 || null
#vendor.address1 #need a break here
end %>
<%= if #vendor.address2 || null
#vendor.address2 #need a break here
end %>
<%= #vendor.city %>, <%= #vendor.state %> <%= #vendor.zip %></p>
This is how I would do it:
<p>
<strong>Main Address</strong>
</p>
<p>
<% unless #vendor.address1.blank? %>
<%= #vendor.address1 %><br>
<% end %>
<% unless #vendor.address2.blank? %>
<%= #vendor.address2 %><br>
<% end %>
<%= #vendor.city %>, <%= #vendor.state %> <%= #vendor.zip %>
</p>
By the way: the || null in your code is not valid Ruby. null does not exist, it should be nil. But even if you had used nil, your code does not do what you expect it to do. For these kind of things, you'd better use blank?.
<p><strong>Main Address</strong></p>
<p><%= #vendor.address1%><%= <br/> if #vendor.address1.blank? %>
<%= #vendor.address2%><%= <br/> if #vendor.address2.blank? %>
<%= #vendor.city %>, <%= #vendor.state %> <%= #vendor.zip %></p>

rails 3: How can I concatenate a number to a symbol?

I would like the #comment1 to change to #comment2 by using the i in the 1..5 loop. I have the following code that is pretty repetitive. I am hoping to dry it up.
Hi,I am using acts_as_commentable_with_threading. I am basically looping through all comments and checking to see if that comment has children. If so, print out the children while checking to see if those children have children. So I plan on going a few levels deep, hence the #comment1,2,3, etc...How can I DRY this? Recursion some how? If not, I could maybe go a few levels deep and end the comment indentation at #comment5 for example.
EDIT!
Thank you Samiron!
Here is the updated helper function...
def show_comments_with_children(comments)
comments.each do |comment|
yield comment
if comment.children.any?
concat <<-EOF.html_safe
<div class="span7 offset1-1 pcomment">
EOF
show_comments_with_children(comment.children) { |x| yield x } #Dont worry, this will not run another query :)
concat <<-EOF.html_safe
</div>
EOF
end
end
end
<div class="span7 offset1-1 pcomment">
<% #comment1 = comment.children%>
<% for comment in #comment1 %>
<%= render "comment_replies", :comment => comment %>
<div class="span7 offset1-1 pcomment">
<% #comment2 = comment.children%>
<% for comment in #comment2 %>
<%= render "comment_replies", :comment => comment %>
<div class="span7 offset1-1 pcomment">
<% #comment3 = comment.children%>
<% for comment in #comment3 %>
<%= render "comment_replies", :comment => comment %>
<% end %>
</div>
....
<%(1..5).each do |i| %>
<% #comment1 = comment.children%>
<% for comment in #comment1 %>
<%= render "comment_replies", :comment => comment %>
<% end %>
<% end %>
Probably you are looking for instance_variable_set.
# Following snippet is not TESTED. It is here to just demonstrate "instance_variable_set"
<%(1..5).each do |i| %>
<% instance_variable_set("#comment#{i}", comment.children) %>
<% for comment in instance_variable_get("#comment#{i}") %>
<%= render "comment_replies", :comment => comment %>
<% end %>
<% end %>
But definitely this is not a recommendable approach. You can share your controller code and what you want to achieve in your view. There must be some way to make it properly DRY. In your post you are always getting comment.children. is it really?
Actual Solution:
Your view code will be like this
#0th level is the top level
<% show_comments_with_children(#comments, 0) do |comment, level|%>
<!-- #Use level to differ the design for different depth-->
<%= render "comment_replies", :comment => comment %>
<%end%>
and add this helper function show_comments_with_children in your helper function. Which will be.
def show_comments_with_children(comments, level)
comments.each do |comment|
yield comment, level
if comment.children.any?
show_comments_with_children(comment.children, level+1) {|x, l| yield x, l} #Dont worry, this will not run another query :)
end
end
end
The manor in which you are defining this code is rather poor, and you should consider defining #comment as an array rather than as independent variables for each #comment1, #comment2, etc..
That said, what you are looking for is the instance_variable_get() method
<(1..5).each do |i| %>
<% instance_variable_set("#comment#{i}", comment.children) %>
<% for comment in instance_variable_get("#comment#{i}") %>
<%= render "comment_replies", :comment => comment %>
<% end %>
<% end %>
This is definitely something good to know but in this case I highly recommend converting you comment instance variables to an array!

Resources