Can one use conditions and loops on a single line in Ruby? - ruby-on-rails

How would one go about turning the following code into the latter?
<div id="faqs">
<% if #faqs.length > 0 %>
<% #faqs.each do |faq| %>
<div class="faq">
<strong>Q:</strong> <%= faq.question %>
<br />
<strong>A:</strong> <%= faq.answer %>
</div>
<% end %>
<% else %>
<p>No FAQs to display.</p>
<% end %>
</div>
<div id="faqs">
<% #faqs.empty? ? content_tag(:p, "No FAQs to display.") : #faqs.each do |faq| %>
<div class="faq">
<strong>Q:</strong> <%= faq.question %>
<br />
<strong>A:</strong> <%= faq.answer %>
</div>
<% end %>
</div>
I'm curious as to whether I can get the latter code to work. The only element of it that is failing at the moment is that the content_tag() is not displaying - this is due to the fact that I'm not using printable ruby tags (<%= # %>) but using them will dump out the FAQ objects underneath the content.
I considered the use of puts() to print the content_tag() while inside the ruby tags but that didn't work.
I've tried to search for this issue but haven't yielded anything useful.
Is this achievable and if so, does it have any benefits other than being prettier?

One way to make the later code to work if you can put the body of the loop in a helper function and return the out put of content_tag from that. The line in view file might be somewhat like this.
<%= #faqs.empty? ? content_tag(:p, "No FAQs to display.") : printList(#faqs) %>
and your printList function will return the output of nested content_tags. You can make a generic list printing function which can be used for any list.
Something so obvious but still shared.

This should work (for clarity, I moved FAQ tag generation in separate helper method):
<div id="faqs">
<%= raw (#faqs.empty? ? content_tag(:p, "No FAQs to display.") : #faqs.map { |faq| faq_div(faq) }.join) %>
</div>
or, perhaps more clean:
<div id="faqs">
<%= content_tag(:p, "No FAQs to display.") if #faqs.empty? %>
<%= raw #faqs.map { |faq| faq_div(faq) }.join %>
</div>
meanwhile, in helpers:
def faq_div(faq)
'<div class="faq"><strong>Q:</strong> %s<br /><strong>A:</strong> %s</div>' % [faq.question, faq.answer]
end

This should work:
<% if #faqs.each do |faq| %>
<div class="faq">
<strong>Q:</strong> <%= faq.question %>
<br />
<strong>A:</strong> <%= faq.answer %>
</div>
<% end.empty? %>
<p>No FAQs to display.</p>
<% end %>

Related

Strange output from rails each do

Rails each do method is acting strangely and I do not know why.
controller
def index
#fabric_guides = FabricGuide.with_attached_image.all.order(:name)
end
index.html.erb
<div class="guide-items">
<%= #fabric_guides.each do |fabric| %>
<div class="guide-container">
<%= link_to fabric_guide_path(slug: fabric.slug) do %>
<%= image_tag fabric.image if fabric.image.attached? %>
<% end %>
<div class="guide-info">
<p class="g-name">
<%= link_to fabric.name,
fabric_guide_path(slug: fabric.slug) %>
</p>
</div>
</div>
<% end %>
</div>
I have two FabricGuide records so I expect two "guide-container" but I get three. Or more precisely I get two guide containers and a third block of text containing all the content from the last FabricGuide record.
I have almost an identical setup for articles and have never encountered this problem. I'd happily share more information if needed. Thank you!
Please remove = equal sign from your each loop of view code
like below :-
<% #fabric_guides.each do |fabric| %>
...
...
<% end %>
you have used this <%= #fabric_guides.each do |fabric| %> in your view that's why it shows all record in DOM.
The expression for erb tags is <% %>
now if we want to print that tag too then we apply <%= %>

Ruby on Rails how to get last query?

I'm having trouble trying to figure out when I reached the end of my query. So what I want to do is list all the records in my database that begin with the letter A which I got however I want to output a message if the query turns out blank. When I try I get a bunch of my custom messages even the query didn't turn out blank. Is there any way to tell if I've reached EOF in ruby on rails?
Sample
<div id = "content-A">
<p>A</p>
<% #animes.each do |anime| %>
<% if anime.aname.starts_with?('A') %>
<%= link_to anime.aname, {:action => 'list'} %>
<% else %>
<p>No anime listed in this Category :( </p>
<%end%>
<%end %>
</div>
I believe you want sth like:
<% animes_group = #animes.group_by {|anime| anime.aname.to_s[0].upcase}
('A'..'Z').each do |letter| %>
<div id="content-<%= letter %>">
<p><%= letter %></p>
<% if animes = animes_group[letter] %>
<% animes.each do |anime| %>
<%= link_to anime.aname, {:action => 'list'} %>
<% end %>
<% else %>
<p>No anime listed in this Category :( </p>
<%end%>
<% end %>
You should consider moving some of the logic to the controller here, however what is to be moved depends on many factors like whether #animes are being used anywhere else etc.

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: DRYing similar but different views

I have a pair of very similar views that render almost identical information, only in one view there are couple of extra columns and in the other the rows link slightly different nested resources. My initial approach was to keep it DRY by using a partial and then placing conditionals throughout the view. The resulting partial looked something like this:
<div id='overview_table'>
<div id="overview_header">
<span id="sort_title" class="title cell">Title<span id="publication_sort_arrow"> ↓</span></span>
<span id="sort_author" class="author cell">Author</span>
<span id="sort_status" class="status cell">Status</span>
<% if #user.present? %>
<span id="sort_impression_date" class="date cell">Date</span>
<span id="sort_impression_vote" class="votes cell">Votes</span>
<span id="sort_children_total" class="children_total cell">Replies</span>
<% end %>
</div>
<span id="sort_method">title ASC</span>
<% #publications.each do |publication| %>
<div class='<%= cycle("odd", "even") %>'>
<% if #user.present? %>
<% link = [#user, publication] %>
<% else %>
<% link = [#group, publication] %>
<% end %>
<%= link_to(link, :remote => true) do %>
<span class="title cell"><%= publication.full_title %></span>
<span class="author cell"><%= publication.authors %></span>
<span class="status cell"><%= publication_status(publication.status) %></span>
<% if #user.present? %>
<span class="date cell"><% if publication.impression_date %><%= publication.impression_date.strftime("%B %d, %Y") %><% end %></span>
<span class="votes cell"><% if publication.impression_vote %><%= publication.impression_vote.to_i %><% end %></span>
<span class="children_total cell"><% if publication.impression_vote %><%= publication.children_total %><% end %></span>
<% end %>
<% end %>
</div>
<% end %>
It worked fine, but the code felt hacky. I ultimately separated these back out into the two different views, though now there's a lot of repeated code. Both approaches feel inadequate. Is there another approach that I'm not considering?
There are different strategies here but in this case if you are just adding some fields, I would do something like this (which is similar to what you are doing).
in my controller I'll set some tag value to true:
#show_val_extra=true
and in my view(probably be a partial so rather than inline code in your example):
<%="something here" unless #show_val_extra.nil? %>
No matter what you are going to have to check and other issues of managing the view in the controller are ugly to me. YMMV but this is what I'd do since it basically makes it to a single value and a single check for when you want different information. Usually, it's in multiple places but you have content in multiple places and a further refactor is easy if the situation arises.

How do I wrap link_to around some html ruby code?

How do I wrap a link around view code? I can't figure out how to pass multiple lines with ruby code to a single link_to method. The result I am looking for is that you click the column and get the show page:
<div class="subcolumns">
<div class="c25l">
<div class="subcl">
<%= image_tag album.photo.media.url(:thumb), :class => "image" rescue nil %>
</div>
</div>
<div class="c75r">
<div class="subcr">
<p><%= album.created_at %></p>
<%= link_to h(album.title), album %>
<p><%= album.created_at %></p>
<p><%= album.photo_count %></p>
</div>
</div>
</div>
link_to takes a block of code ( >= Rails 2.2) which it will use as the body of the tag.
So, you do
<%= link_to(#album) do %>
html-code-here
<% end %>
But I'm quite sure that to nest a div inside a a tag is not valid HTML.
EDIT: Added = character per Amin Ariana's comment below.
Also, this may be an issue for some:
Make sure to write <%= if you are doing a simple link with code in it instead of <%.
e.g.
<%= link_to 'some_controller_name/some_get_request' do %>
Hello World
<% end %>
For older Rails versions, you can use
<% content_tag(:a, :href => foo_path) do %>
<span>Foo</span>
<% end %>
You can use link_to with a block:
<% link_to(#album) do %>
<!-- insert html etc here -->
<% end %>
A bit of a lag on this reply I know -- but I was directed here today, and didn't find a good answer. The following should work:
<% link_to raw(html here), #album %>

Resources