How to improve code in Views on Ruby on Rails - ruby-on-rails

I have code in file views name: _result.html.erb, this file is rendered from file show.html.erb, both file in one folder
File _result.html.erb
<% if #lesson.answers.at(f.index).is_correct %>
<% if #lesson.answers.at(f.index).id == answer.id %>
<li class="text-success">
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
<% else %>
<li>
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
<% end %>
<% else %>
<% if #lesson.answers.at(f.index).id == answer.id %>
<li class="text-danger">
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
<% else %>
<li>
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
<% end %>
<% end %>
And I want to improve this code in file _result.html.erb for shorter, help me please!!!
File show.html
<% provide :title, t("start_lesson") %>
<h1><%= #course.name %></h1>
<h2><%= #course.description %></h2>
<h3><%= t "title_question" %></h3>
<% if #lesson.finished.present? %>
<h4>
<%= t "score" %>:
<%= #lesson.results.is_correct_answers.count %> /
<%= #lesson.words.count %>
</h4>
<% end %>
<%= form_for [#course, #lesson] do |f| %>
<%= f.fields_for :results do |builder| %>
<ul class="list-unstyled">
<li>
<%= "#{builder.index + 1}." %>
<%= #words.at(builder.index).content %>
</li>
<ul class="list-unstyled">
<% #words.at(builder.index).answers.each do |answer| %>
<% if #lesson.finished.nil? %>
<li>
<%= answer.content %>
<%= builder.radio_button :answer_id, answer.id %>
<%= builder.hidden_field :word_id, value: answer.word.id %>
</li>
<% else %>
<%= render "result", f: builder, answer: answer %>
<% end %>
<% end %>
</ul>
</ul>
<% end %>
<% if #lesson.finished.nil? %>
<%= f.submit t("submit"), class: "btn btn-primary" %>
<% end %>
<% end %>

This is just a code-rewrite exercise, so here goes:
result.html.erb
<% if #lesson.answers.at(f.index).id == answer.id %>
<% if #lesson.answers.at(f.index).is_correct %>
<li class="text-success">
<% else %>
<li class="text-danger">
<% end %>
<% else %>
<li>
<% end %>
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
or the shorter (but much harder to read) version:
<li<% if #lesson.answers.at(f.index).id == answer.id %>class="<%= #lesson.answers.at(f.index).is_correct ? "text-success" : "text-danger" %>" <% end%>>
<%= f.radio_button :answer_id, answer.id, disabled: true %>
<%= answer.content %>
</li>
In the first example, the condition was inverted to take advantage of the fact that the else condition in both interior conditions was identical, and then using the conditions only to style the <li> node, since that was the only difference between the 4 blocks.
The second example goes further and does the conditional checks inline with the element, building the class attribute when necessary. This is much harder to read at a glance, but is far more compact.
show.html
<% provide :title, t("start_lesson") %>
<h1><%= #course.name %></h1>
<h2><%= #course.description %></h2>
<h3><%= t "title_question" %></h3>
<% if #lesson.finished.present? %>
<h4><%= "#{t 'score'}: #{#lesson.results.is_correct_answers.count} / #{#lesson.words.count} %></h4>
<% end %>
<%= form_for [#course, #lesson] do |f| %>
<%= f.fields_for :results do |builder| %>
<ul class="list-unstyled">
<li><%= "#{builder.index + 1}.#{#words.at(builder.index).content}" %></li>
<ul class="list-unstyled">
<% #words.at(builder.index).answers.each do |answer| %>
<% if #lesson.finished.nil? %>
<li>
<%= answer.content %>
<%= builder.radio_button :answer_id, answer.id %>
<%= builder.hidden_field :word_id, value: answer.word.id %>
</li>
<% else %>
<%= render "result", f: builder, answer: answer %>
<% end %>
<% end %>
</ul>
</ul>
<% end %>
<% if #lesson.finished.nil? %>
<%= f.submit t("submit"), class: "btn btn-primary" %>
<% end %>
<% end %>
Most of the changes here are just using string interpolation to combine string elements that are otherwise multiple <%= %> blocks.
The larger loop portion that builds the list of answers has some possible issues. For instance, the rendered result (when the lesson is not finished) is missing the <li> and </li> elements, so the answers are simply sitting as a blob of text within the enclosing <ul>. In order to preserve that, in case it was intentional, most of the middle block remained.
However, this is probably not what you actually wanted, so this version fixes that and does a little more reorganization:
<% provide :title, t("start_lesson") %>
<h1><%= #course.name %></h1>
<h2><%= #course.description %></h2>
<h3><%= t "title_question" %></h3>
<% if #lesson.finished.present? %>
<h4><%= "#{t 'score'}: #{#lesson.results.is_correct_answers.count} / #{#lesson.words.count} %></h4>
<% end %>
<%= form_for [#course, #lesson] do |f| %>
<%= f.fields_for :results do |builder| %>
<ul class="list-unstyled">
<li><%= "#{builder.index + 1}.#{#words.at(builder.index).content}" %></li>
<ul class="list-unstyled">
<% #words.at(builder.index).answers.each do |answer| %>
<li>
<% if #lesson.finished.nil? %>
<%= answer.content %>
<%= builder.radio_button :answer_id, answer.id %>
<%= builder.hidden_field :word_id, value: answer.word.id %>
<% else %>
<%= render "result", f: builder, answer: answer %>
<% end %>
</li>
<% end %>
</ul>
</ul>
<% end %>
<% if #lesson.finished.nil? %>
<%= f.submit t("submit"), class: "btn btn-primary" %>
<% end %>
<% end %>
That's about the shortest this can be without collapsing the structure or just removing whitespace. Each remaining element seems to have a purpose and is placed where it should be, without redundancy or over-complication.

Related

How can I separate my pics and videos so only the one the user post is displayed?

I am trying to write an if else statement so that when a users post a photo only the photo is displayed the same goes for videos. Right now if a users post a video a blank photo will be displayed under the video as well. My code is below. I know it has something to do with the lines:
<%= image_tag #post.image.url(:medium) %>
<%= video_tag #post.video.url(:medium), controls: true, type: "video/mp4" %>
I just don't know what the best way is to only show the one the user is posting.
Post/Show.html
<div class="row">
<div class="col-md-offset-4 col-med-8">
<div class="panel panel-default">
<div class="panel-heading center">
<%= image_tag #post.image.url(:medium) %>
<%= video_tag #post.video.url(:medium), controls: true, type: "video/mp4" %>
</div>
<div class="panel-body">
<p><%= #post.description %></p>
<p><strong><%= #post.user.name if #post.user %></strong></p>
<% if #post.user == current_user %>
<%= link_to edit_post_path(#post) do %>
<span class="glyphicon glyphicon-edit"></span>
Edit
<% end %>
<% end %>
<%= link_to 'Back', posts_path %>
</div>
</div>
Form
<%= form_for #post, html: { multipart: true } do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :image %>
<%= f.file_field :image %>
</div>
<div class="field">
<%= f.label :video %>
<%= f.file_field :video %>
</div></br>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="actions">
<%= f.submit class: "btn btn-danger btn-md" %>
</div>
<% end %>
if i understand you correctly, you could try this...
<% if #post.respond_to?(:image) %>
<%= image_tag #post.image.url(:medium) %>
end
<% if #post.respond_to?(:video) %>
<%= image_tag #post.video.url(:medium), controls: true, type: "video/mp4" %>
end
You are basically checking for the existence of the particular attribute. You are saying, if it is here, if it exists, then display it.
Or you could try this
<% if #post.image.url != nil %>
<%= image_tag #post.image.url(:medium) %>
.........(repeat for other attributes)
<% end %>
or this
<% unless #post.image.url == nil %>
<%= image_tag #post.image.url(:medium) %>
<% end %>
see here for more info.
There are many ways to achieve what you want. this kind of thing is one of the fundamental concepts of programming.

How to customise rails validation error messages with a nested form setup

I have a form with a nested object something like this:
<%= form_for(#person) do |f| %>
<% if #person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#person.errors.count, "error") %> prohibited this record from being saved</h2>
<ul>
<% #person.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render 'person_fields', f: f, :person => #person %>
<%= f.fields_for :posts do |builder| %>
<%= render 'post_fields', f: builder %>
<% end %>
<br />
<div class="actions">
<%= f.submit %>
</div>
<% end %>
The thing is the validation error messages come up in the format {attribute}{message}, i.e the regular full_messages format. The {attribute} also includes the model name which isn't what I want, I just want to display the attribute and the message.
I'm thinking I can potentially us the rails internationalisation api but could use some guidence; has anyone else managed to do this?
I worked out how to this... just for reference, here's my solution:
<%= form_for(#person) do |f| %>
<% #person.errors.messages.each do |msg| %>
<% msg[1].each do |m| %>
<% if msg[0].to_s.split(".")[-1] == "base" %>
<li><%= m %></li>
<% else %>
<li><%= msg[0].to_s.split(".")[-1].humanize.titlecase %> <%= m %></li>
<% end %>
<% end %>
<% end %>
<%= render 'person_fields', f: f, :person => #person %>
<%= f.fields_for :posts do |builder| %>
<%= render 'post_fields', f: builder %>
<% end %>
<br />
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I've used the custom-err-msg plugin in the past and had a lot of success.

If Condition in each do Rails

Hi i need to print out just the candidates where active is == 0 here is my code in the view.
I can print if active is yes or no.. But in the each do loop i just want to print the active candidates.
So how can i add the condition to my each do loop, thanks.
<% #candidates.each do |candidate| %>
<div id="candidateper">
<div class="avatth" ><div class="avat_min">
<% if candidate.avatar.present? %>
<%= link_to (image_tag candidate.avatar.url(:thumb)), (candidate_path(candidate)) %>
<% else %>
<%= link_to (image_tag ("espanol/playersample.png")), (candidate_path(candidate)) %>
<% end %>
</div></div>
<div class="nameth"><%= candidate.name %></div>
<div class="activeth"><%= candidate.active ? t('generales.yess') : t('generales.noo') %></div>
<div class="generalth">
<% if candidate.user.purchased_at.present? %>
<%= candidate.user.purchase_defeated? ? t('generales.defeated') : t('generales.active') %>
<% else %>
<%= t('generales.noo') %>
<% end %>
</div>
<div class="actionsth"><%= link_to t('generales.show'), candidate_path(candidate) %>
<% if current_user.user_type == 'admin' %>
<%= link_to t('generales.delete'), candidate_path(candidate), method: :delete, data: { confirm: t('generales.delete_candidate_confirm') } %>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
I`ve tried this
no luck syntax error on all my ideas :P
If candidate.active is actually a boolean then you could say:
<% #candidates.reject(&:active).each do |candidate| %>
...
<% end %>
If #candidates is actually an ActiveRecord::Relation then you could probably say:
<% #candidates.where(:active => false).each do |candidate| %>
...
<% end %>
to avoid pulling a bunch of stuff out of the database when you don't want it.
If active is actually a number (inside the database and outside the database) then you could say:
<% #candidates.select(&:zero?).each do |candidate| %>
...
<% end %>
or
<% #candidates.where(:active => 0).each do |candidate| %>
...
<% end %>

link_to in ruby on rails with additional html

I know there are more of these, but I couldn't find my answer as I'm still fairly new to RoR.
I need to take this:
<% if params[:forum_id] %>
<%= link_to "#{category.name}", category_path(category.id,:forum_id => params[:forum_id]) %>
<% else %>
<%= link_to "#{category.name}", category_path(category.id) %>
<% end %>
which prints out:
name
and I need:
<a href="mylink....">
<figure></figure>
<span>name</span>
</a>
Thanks!
You can use link_to as a block:
<%= link_to category_path(category_id) do %>
<figure></figure>
<span><%= category.name %></span>
<% end %>
EDIT
The full solution:
<% if params[:forum_id] %>
<%= link_to category_path(category.id,:forum_id => params[:forum_id]) do %>
<figure></figure>
<span><%= category.name %></span>
<% end %>
<% else %>
<%= link_to category_path(category.id) do %>
<figure></figure>
<span><%= category.name %></span>
<% end %>
<% end %>

Whats wrong with this else if statement?

Basically my controller is just grabbing all members: #members = Member.all and Im looping through them while checking to see if they have a profile picture uploaded and if not then the default should be loaded:
<% #members.each do |member| %>
<% unless member.image.nil? %>
<li style="float:left; width:100px;">
<%= image_tag(member.image.url(:tiny)) %>
<%= link_to member.email, member_path(member) %>
</li>
<% else %>
<li style="float:left; width:100px;">
<%= image_tag("default_member_small.jpg") %>
<%= link_to member.email, member_path(member) %>
</li>
<% end %>
<% end %>
It seems to think every member has a profile image, and the image tag is calling "images/tiny/missing.png" for the missing images.
What gives?
I am guessing you are using paperclip, if you are, you should not use nil?, you should use present?:
<% #members.each do |member| %>
<% if member.image.present? %>
<li style="float:left; width:100px;">
<%= image_tag(member.image.url(:tiny)) %>
<%= link_to member.email, member_path(member) %>
</li>
<% else %>
<li style="float:left; width:100px;">
<%= image_tag("default_member_small.jpg") %>
<%= link_to member.email, member_path(member) %>
</li>
<% end %>
<% end %>
And instead of having an if you should just have this image named as paperclip expects it, there should not have any ifs in your code for this kind of handling.

Resources