Indentation in ERB templates - ruby-on-rails

I have the following entry in an erb template:
# Lorem Ipsum...
<% unless #foo['bar'] == nil %>
<% #foo['bar'].each do |property, value| %>
<%= "zaz.#{property} #{value}" %>
<% end %>
<% end %>
That is parsed to:
# Lorem Ipsum...
zaz.property value
How can I remove the leading spaces so that lines are not indented in the resolved template?
I would like to avoid using something like:
# Lorem Ipsum...
<% unless #foo['bar'] == nil %>
<% #foo['bar'].each do |property, value| %>
<%= "zaz.#{property} #{value}" %>
<% end %>
<% end %>

The only solution I can offer is hackish adding <%- 'whatever here' %> before the <%= %> entry:
<% [1,2,3].each do |f| %>
<%- 1 %><%= f %>
<% end %>
it outputs in irb
irb(main):018:0> ERB.new(File.read('f.txt'), nil, '-').result
=> "\n1\n\n2\n\n3\n\n"
Rails doc claims, that default value for ERB trim_mode is -
http://edgeguides.rubyonrails.org/configuring.html#configuring-action-view
And according to https://www.systutorials.com/docs/linux/man/1-erb/ ERB should remove spaces before <%- when - mode is enabled.

You could indent the code instead of the ERB tags:
# Lorem Ipsum...
<% unless #foo['bar'] == nil %>
<% #foo['bar'].each do |property, value| %>
<%= "zaz.#{property} #{value}" %>
<% end %>
<% end %>

If you're controlling the string passed to ERB.new, then you can make yourself a new tag to use.
Given a template in a file:
<%~ 'hello' %>
<%~ 'world' %>
<%~ '!' %>
Do:
string = File.read(file_path).gsub('<%~', '<%-%><%=')
print ERB.new(string, trim_mode: '-').result
And get:
hello
world
!
I'd love it if ERB would include this tag itself, but until then I'm doing it myself.

Related

The result repeats the message several times with ruby on rails

I have this code:
<% #lookup_coins.each do |x| %>
<% if #symbol == '' %>
<%= 'Sorry, but you forgot to write something, LOL'%>
<% elsif #symbol == x %>
<%= x["symbol"]%> <br/> <%= x["name"]%>: <%= number_to_currency(x['quote']['USD']['price'].round(2) , :unit => "$ ") %> <br/> <%= x["cmc_rank"]%> <br/>
<% else 'Sorry, there was a mistake, try again'%>
<% end %>
The info looks like this:
[{"id"=>1, "name"=>"Bitcoin", "symbol"=>"BTC", "slug"=>"bitcoin", "num_market_pairs"=>9713, "date_added"=>"2013-04-28T00:00:00.000Z", "tags"=>["mineable", "pow", "sha-256", "store-of-value", "state-channels", "coinbase-ventures-portfolio", "three-arrows-capital-portfolio", "polychain-capital-portfolio"], "max_supply"=>21000000, "circulating_supply"=>18633612, "total_supply"=>18633612, "platform"=>nil, "cmc_rank"=>1, "last_updated"=>"2021-02-20T07:45:02.000Z", "quote"=>{"USD"=>{"price"=>55541.51774356704, ...
I am not sure how to do it in the correct way
It looks like you're failing to match to the actual symbol value, but instead are expecting #symbol to perfectly match a Hash, which it won't.
Secondly, you're also printing that "forgot to write something" message each time through the loop which is wrong. You can get rid of the loop, just use find to locate the entry right away, and then as a bonus you can more easily detect a "missed" condition.
Just see if you can find a matching entry, otherwise display the message.
The fix looks like:
<%- if #symbol.blank? -%>
Sorry, but you forgot to write something.
<%- else -%>
<%- found = #lookup_coins.find { |c| c['symbol'] == #symbol } -%>
<%- if (found) -%>
<%= found["symbol"]%> <br/> <%= found["name"]%>:
<%= number_to_currency(found['quote']['USD']['price'].round(2), :unit => "$ ") %>
<br/>
<%= found["cmc_rank"]%> <br/>
<%- else -%>
Sorry, there was a mistake, try again
<%- end -%>
<%- end -%>
Using #symbol.blank? here which is more forgiving than == '' as it will also reject a bunch of spaces and/or tabs.
Tip: Don't use <%= '...' %> Instead just put the text there as-is. The default is to echo it.
<% if #symbol %>
<%#resultant_symbol = #lookup_coins['data'].select {|lookup_coin| lookup_coin["symbol"] == #symbol }%>
<%if #resultant_symbol.present?%>
<% x = #resultant_symbol.first %>
<%= x["symbol"]%> <br/> <%= x["name"]%>: <%= number_to_currency(x['quote']['USD']['price'].round(2) , :unit => "$ ") %> <br/> <%= x["cmc_rank"]%> <br/>
<%else%>
<%= #symbol = 'Sorry, there was a mistake, try again'%>
<%end%>

Ruby is adding weird spacing between words

My website is printing out elements such as (SnO), however, it should be printing SnO, but it is adding a weird space and it is printing like Sn O. It is adding a space between the element for no reason. My code is on the listed below.
<% saved_element = ""%>
<% sensor.base_material.elests.each_with_index do |elest, v| %>
<% if elest.element.include? "O" %>
<% saved_element = elest %>
<% else %>
<%=elest.element.split('-').last %>
<% if elest.stoich != 1 %>
<sub><%=elest.stoich.to_i%></sub>
<% end %>
<% end %>
<% if v == sensor.base_material.elests.length-1 %>
<%=saved_element.element.split('-').last%>
<% if saved_element.stoich != 1 %>
<sub><%=saved_element.stoich.to_i %></sub>
<% end %>
<% end %>
<% end %>
The code you show is full of white spaces (at the beginning of each line). Those are printed on the HTML and compacted as one space. Also, when you print a value, it adds an space at the end, you can supress that usign <%= ... -%> (note the dash at the end)
https://www.howtobuildsoftware.com/index.php/how-do/Nzr/ruby-on-rails-erb-suppressing-spaces-in-erb-template
Anyway, I would move all that logic to a helper method, that's what helper methods are for.

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 "".

Dont have a comma on the last iteration of an each loop in Rails

I want to print out a list of links separated by commas in Rails.
Heres what I've got:
<%= topics.each do |topic| %>
<a href="<%= topic.link %>" ><%= topic.name %></a>
,
<% end %>
Heres what I want:
Thing A,
Thing B,
Thing C
But right now I get an extra comma on the last iteration of the loop! What should I do?
One way of doing this is with map then Array#join:
<%= topics.map { |topic| link_to(topic.name, topic.link) }.join(',').html_safe %>
if you want to do minimum possible change to your code, you can use the following
<%= topics.each do |topic| %>
<a href="<%= topic.link %>" ><%= topic.name %></a>
<% if(topic != topics.last) %>
,
<% end %>
<% end %>
How about using each_with_index, and only put comma before the content unless it's not the first item.
<% topics.each_with_index do |topic, i| %>
<% if i > 0 %>
,
<% end %>
<%= topic.name %>
<% end %>
I made it in one line call (for active records collections) using the concat helper:
<% concat (',') if e.bills.last != b %>
concat is an ERB helper (TextHelper) to add some HTML without the <%= %> syntax, helpful to add few characters.
Here is the full code to make it clear:
<% event.bills.each do |b| %>
<%= link_to(b.number.to_s, bill_display_path(b)) %>
<% concat (',') if e.bills.last != b %>
<% end %>
Simply try this. It works for me
<%= topics.map{|p| p.topic.name}.join(",") %>
You can do the following to print out the comma for all items except for the last:
<% topics.each do |topic| %>
<%= topic %>
<%= "," if topic != topics.last %>
<% end %>
This will check if the current item in the loop is the last item, and will use the <%= %> syntax to output the comma.

Rails erb formatting troubles, phantom spaces

Halp! My template is formatting strangely and I can't fathom how/why.
<% #poll.questions_all.each do |q| %>
<td>
<span class="optionvalue">
<% if can? :read_full, #poll %>
<%= resp[:texts][q.id] %>
<% else %>
<%= resp[:texts][q.id].nil? ? '' : resp[:texts][q.id].gsub(Question::POISON_WORDS_REGEX, '---') %>
<% end %>
</span>
<% unless q.options.empty? %>
<%= q.get_matching_option(resp[:texts][q.id])? ": #{q.get_matching_option(resp[:texts][q.id])}" : '' %>
<% end %>
</td>
<% end %>
Results in this:
A : Playgrounds
No idea where that first space is coming form, and every effort to get rid of it has failed! The generated markup:
<td>
<span class="optionvalue">
A
</span>
: Playgrounds
</td>
Try using the <%- -%> version of erb tags, these should suppress the extra whitespaces:
<%- if can? :read_full, #poll -%>
<%= resp[:texts][q.id] %>
<%- else -%>
<%= resp[:texts][q.id].nil? ? '' : resp[:texts][q.id].gsub(Question::POISON_WORDS_REGEX, '---') %>
<%- end -%>
I don't recall if you need them in both the opening and ending tags, but I'd suggest playing around with it and see if you can get what you want.
Horrible solution, but it works:
<% #poll.questions_all.each do |q| %>
<td>
<span class="optionvalue">
<% if can? :read_full, #poll %>
<%= resp[:texts][q.id] %></span><%= q.get_matching_option(resp[:texts][q.id])? ": #{q.get_matching_option(resp[:texts][q.id])}" : '' unless q.options.empty? %>
<% else %>
<%= resp[:texts][q.id].nil? ? '' : resp[:texts][q.id].gsub(Question::POISON_WORDS_REGEX, '---') %></span><%= q.get_matching_option(resp[:texts][q.id])? ": #{q.get_matching_option(resp[:texts][q.id])}" : '' unless q.options.empty? %>
<% end %>
</td>
<% end %>
I am pretty sure erb will do the right thing (not add unwanted lines) if you keep everything on one line of HTML.
For this case, and in general, I recommend that you put any logic for generating the content in methods in the view helper file (or if you're feeling lazy, in a code block in the erb, as in this example):
<% #poll.questions_all.each do |q| %>
<%
if can? :read_full, #poll
texts = resp[:texts][q.id]
else
texts = (resp[:texts][q.id].nil? ? '' : resp[:texts][q.id].gsub(Question::POISON_WORDS_REGEX, '---'))
end
if q.options.empty?
matching_options = ''
else
matching_options = (q.get_matching_option(resp[:texts][q.id])? ": #{q.get_matching_option(resp[:texts][q.id])}" : '')
end
%>
<td>
<span class="optionvalue"><%= texts %></span><%= matching_options %>
</td>
<% end %>

Resources