Rails - Use a Helper or a Partial [duplicate] - ruby-on-rails

This question already has answers here:
When to use Helpers instead of Partials
(6 answers)
Closed 7 years ago.
In my Article model, I have 4 different columns: short_effects, long_effects, benefits, and alternatives. They are all text columns.
In my view, I am calling each one in the same basic format:
<% unless #article.short_effects.blank? %>
<hr id="effects">
<h2><span class="glyphicon glyphicon-hourglass"></span>Short-term side effects</h2>
<ul>
<% #article.short_effects.split(';').each do |effect| %>
<li><%= effect.downcase %></li>
<% end %>
</ul>
<% end %>
<% unless #article.long_effects.blank? %>
<hr id="effects2">
<h2><span class="glyphicon glyphicon-time"></span>Long-term side effects</h2>
<ul>
<% #article.long_effects.split(';').each do |effect| %>
<li><%= effect.downcase %></li>
<% end %>
</ul>
<% end %>
.
.
.
to eliminate repetition, I would like to create a helper or a partial... however, I do not know which is better for this situation. I know some people frown upon HTML inside of helpers, but since helpers are used to reduce code from views, I feel that may be the best way. Any advice is greatly appreciated.

There are some existing discussions about this one here. In particular, this question has a variety of (mostly short) answers with some good rules-of-thumb you might consider. I would personally be of the "minimize HTML in a helper" school of thought, however I also like the description of helpers being for specific elements while using partials for larger chunks of code.

Related

How much should I avoid computations in my views?

I am building an application where n users can talk to each other (like a messaging application) in public. Because you might want to have a different bio for each talk you do (for example a discussion about me regarding Ruby on Rails would need a different bio than one about Psychology) I have a Spkr model which has a User and a Tlk. The below code successfully means that on the users profile page, for each instance of them being a Spkr, the Tlk, and it's participants is visible with each Spkr's image (so if a Tlk has three participants, then all three images will be visible).
The setup is such where the default image is the User's image, but the Spkr can also customise their image by uploading one as a Spkr. I am worried that I am loading the front end with too much computation. Right now everything works... so is it ok? Or should I be limiting the computation happening when building views?
Thank you
<% #user.spkrs.each do |spkr| %>
<%= link_to show_tlk_path(spkr.tlk) do %>
<h4><%= spkr.tlk.title %></h4>
<% spkr.tlk.spkrs.each do |speaker| %>
<div class="tlk-tlking-image spkr-image image-spkr-<%= spkr.id %>"
<% if speaker.image.present? %>
style="background-image: url(<%= rails_blob_url(speaker.image) %>)"
<% elsif speaker.user.image.present? %>
style="background-image: url(<%= rails_blob_url(speaker.user.image) %>)"
<% end %>
>
</div>
<p><%= speaker.name %></p>
<% end %>
<% end %>
<% end %>
It tends to be considered good practice to keep the view as free of 'back end' calculations as possible. These files are often worked on by front end developers who may not even know how to code ruby, so the less of it that is in the view the better. It's also just not where it belongs in rail's Model Controller View framework.
First of all the code you've put can be simplified to:
<% #user.spkrs.each do |spkr| %>
<%= link_to show_tlk_path(spkr.tlk) do %>
<h4><%= spkr.tlk.title %></h4>
<% spkr.tlk.spkrs.each do |speaker| %>
<div class="tlk-tlking-image spkr-image image-spkr-<%= spkr.id %>"
style="background-image: url(<%= rails_blob_url((speaker.image || speaker.user.image) %>)"
>
</div>
<p><%= speaker.name %></p>
<% end %>
<% end %>
<% end %>
But as you say, if you want to handle this in a more appropriate place, I'd add a method to the Speaker class:
# app/models/speaker.rb
class Speaker << ApplicationBase
def image_for_view
image || user.image
end
end
This will let you call speaker.image_for_view which I think reads nicely in the view file itself.
Along with the great answer let me just add something that might help you to make views more clear. Might not be relevant to your question directly but might help you to get some idea how you can make views beautiful.
The first thing to make views look good are helpers. Though rails provide helpers for every controller, helpers are global meaning it can be used anywhere in any views. So, global formatings should be done with helpers. Like if you want a date formatter that needs to be used in a lot of view files, you can create a helper called date_helper.rb in app/helpers and put you desired date formatting -
module DateHelper
def formatted_date(date)
date.strftime([%m/%d/%Y')
end
end
Next is what rails people like to call a Presenter pattern. This is helpful when you don't want some logic to be shared across all views. Some logic that doesn't feel like belongs in controller or model are put there to make views readable. Suppose you have a view like below which is a bit messy -
<p>
Post title: <%= post.title.gsub("forbidden word", "") %>
<%= link_to "Read post", post, class: "w-75 p-3 text-#{post.draft? ? "orange" : "green"} border-#{post.draft? ? "orange" : "green"}" %>
</p>
To make this more beautiful you can create a presenter class named post_presenter.rb which should reside in app/presenters and write some code like -
class PostPresenter
def initialize(post)
#post = post
end
def title_without_forbidden_words
#post.title.gsub("forbidden word", "")
end
def css_color
#post.draft? ? "orange" : "green"
end
end
and in the view -
<% presenter = PostPresenter.new(post) %>
<p>
Post title: <%= presenter.title_without_forbidden_words %>
<%= link_to "Read post", post, class: "w-75 p-3 text-#{presenter.css_color} border-#{presenter.css_color}" %>
</p>
Such way a view might be more clear and also it can be lifesaver for frontend developers. This are the best two methods I found till now that makes a rails view beautiful which I always try to use.
Examples are taken from rubyguides website. Thanks to them,

Why many people use "-%>" instead of "%>" in Rails? [duplicate]

This question already has answers here:
What is the difference between <%, <%=, <%# and -%> in ERB in Rails?
(7 answers)
Closed 8 years ago.
Sorry for this question, i think its more offtopic, but i couldn't find anything on google!
I saw now multiple times that a lot of people use -%> instead of just %>. Whats the sense?
Example:
<% #images.each_slice(6) do |slice| -%>
<div class="gallery">
<% slice.each do |image| -%>
<%= image_tag(image.url, :alt => image.alt) %>
<% end -%>
</div>
<% end -%>
Source: Rails each loop insert tag every 6 items?
Here he has also used -%> for all blocks.
I would like to add some resources that I know about ERB :
Rails extends ERB, so that you can suppress the newline simply by adding a trailing hyphen to tags in Rails templates:
<ul>
<% for #item in #items -%>
<li><%= #item %></li>
<% end -%>
</ul>
Comment markers use a hash sign:
<%# This is just a comment %>
A tag with an equals sign indicates that enclosed code is an expression, and that the renderer should substitute the code element with the result of the code (as a string) when it renders the template. Use an expression to embed a line of code into the template, or to display the contents of a variable:
Hello, <%= #name %>.
Today is <%= Time.now.strftime('%A') %>.
With one equal sign the string will be encoded. To avoid encoding, you can use two equals signs (or raw):
Hello, <%== #unencodedOutput %>
Tags without the equals sign denote that the enclosed code is a scriptlet. Each scriptlet is caught and executed, and the final result of the code is then injected in to the output at the point of the scriptlet.
<ul>
<% for #item in #shopping_list %>
<li><%= #item %></li>
<% end %>
</ul>
Scriptlets are most commonly used for embedding loops or conditional logic into templates:
Read An Introduction to ERB Templating to know more.

Stuck trying to list associated model

I think I am deeply misunderstanding how to write instances.
Miniatures have_many Manufacturers through the Productions table.
On the miniatures show page I am trying to list all the manufacturers for the current miniature and have them link the Manufacturer show page. Like so:
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to #miniature.manufacturer.name, manufacturer_path %>
<% end %>
Needless to say it does not work. It gives "undefined method `manufacturer'".
I have tried A LOT of different combinations to no avail. The following version puts all the manufacturers, rolled into one link, once for each manufacturer a miniature has, and links to /manufacturers. A big mess.
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to #miniature.manufacturers.map(&:name).join(', '), manufacturer_path %>
<% end %>
I have been working on other things and hoping I would get the hang of this but I'm pretty sure it's something pretty fundamental about how I set up the instance.
If it's more likely something I need to add to the controller then I can add my controller code here. Any help much appreciated.
Does this work:
<% #miniature.manufacturers.each do |manufacturer| %>
<%= link_to manufacturer.name, manufacturer_path(manufacturer) %>
<% end %>

Is It Possible To Use Variables To Build a link_to Command? (Rails 3.2.11)

I am creating a section of my Rails application for the visually impaired. This requires me to create it using only text and links in order to make it easier for people using speech readers to navigate through. I want to use fields from an existing model to dynamically build a link_to command. I would like to be able to build a variable using several fields on the model that contains the text that a user clicks on and another field from the model which contains the link.
Here is the code in my controller:
MediaLibrary.find(:all, conditions: ["media_type_id < ?", 3], limit: 5).each do |media_item|
#audio_links["link_text"] = "Audio of #{MediaCreator.find(media_item.media_creator_id).name} #{media_item.media_created.to_time.strftime('%A, %B %d, %Y')} at #{media_item.meeting_time}
#{media_item.am_pm} - #{media_item.name}"
#audio_links["link"] = media_item.link
end
Here is the code in my view:
<% #audio_links.each do |audio_link| %>
<li>
<%= link_to audio_link["link_text"], '#{audio_link["link"]}' %>
</li>
<% end %>
I have also tried the following:
<% #audio_links.each do |audio_link| %>
<li>
<%= link_to 'audio_link["link_text"]', '#{audio_link["link"]}' %>
</li>
<% end %>
And this:
<% #audio_links.each do |audio_link| %>
<li>
<%= link_to '#{audio_link["link_text"]}', '#{audio_link["link"]}' %>
</li>
<% end %>
I have tried a few more variations but I either get the can't convert String into Integer error on the link_to command when I attempt to display the screen or the links display with the text being displayed as the following. When this happens I get other errors when I click the link.
#{audio_link["link_text"]}
I have done a lot of searches on Stack Overflow and throughout the web. I have not found a single example of this being done anywhere. I have seen in older posts where there was a set_path command (2010) but nothing for recent posts. I have used html_safe! before and will add that to my code. I do not know if there is a problem with my code or if I am attempting something that is not possible. I sincerely hope this is possible because it will make it easier for people with speech readers to know what they are clicking on.
Any help with this would be appreciated.
You can't do string interpolation in single quotes. Replace the single quotes with double quotes and your variables will be expanded properly.
For example:
<%= link_to audio_link["link_text"], "#{audio_link['link']}" %>

Rails - Best way / how to create Date-based Nav

I'm new to rails and am working on extending the functionality of my basic blog app. What I would like to do is create date-based navigation links. For example, I would like to have a list of links with the names of the months (as the links) and when you click on the month it shows you all the articles published in that month.
I'm struggling with how to best accomplish this.
Should I create a new Model / View / Controller for something like an ArticleArchive? Or is the solution more simple based on my needs?
I've searched the other posts in the community and none seemed to answer this. Any help with how to structure this and possibly implement is appreciated. Thanks!
Here's an example on approaching this, although in this I wanted to sort it by day. This is for your controller action:
def index
#article_days = Article.all.group_by{ |r| r.published_at }
end
To modify this to months, you'd want to do something like r.published_at.beginning_of_month in the example above and essentially group_by the name of the month.
In the view template:
<% #article_days.sort.each do |pub, articles| %>
<h3><%= pub.strftime('%e %A, %B %Y') %></h3>
<% for article in articles %>
<%= article.title %><br/>
<%= article.summary %>
<% end %>
<% end %>
There's a screencast on this as well.
UPDATE
OK - so you only want the names of the month appearing. Keep the instance variable we setup in your index action along with your other code (you probably have setup #articles = Article.all). Then where you want the links listed do:
<% #article_months.sort.each do |pub, articles| %>
<h3><%= pub.strftime('%B') %></h3>
<% for article in articles %>
<%= link_to "#{article.title}", article_path(article) %>
<% end %>
<% end %>

Resources