IF/ELSE Conditions on Ruby hash - html

I want to set up a Ruby partial that takes a 'type' then, depending on that type, spits out a <li> with defined elements (such as an icon, a particular label, etc)
Here's my working .erb chunk
<ul>
<% if locals.has_key? :sermon_links %>
<% sermon_links.each do |link| %>
<% if locals.has_key? :type == "download" %>
<li>
<i class="material-icons">music_note</i>
Download this sermon (~5mb)
</li>
<% else %>
<% if locals.has_key? :type == "passage" %>
<li>
<i class="material-icons">link</i>
<%= sermon_passage %> on Bible Gateway
</li>
<% end %>
<% end %>
<% end %>
</ul>
And then I'd call it in the HTML file like this:
:sermon_links => [
{ :type => "download", :hyperlink => "https://www.biblegateway.com/resources/matthew-henry/John" }
]
I'm 99% sure the problem is how I'm setting the 'IF type equals THIS' (<% if locals.has_key? :type == "download" %>) I'm a newbie to Ruby on Rails so any help in this area would be really appreciated :) thanks!

I think you can rewrite as follows:
<ul>
<% if locals.has_key? :sermon_links %>
<% sermon_links.each do |link| %>
<% if link[:type].present? && link[:type] == "download" %>
<li>
<i class="material-icons">music_note</i>
Download this sermon (~5mb)
</li>
<% else %>
<% if link[:type].present? && link[:type] == "passage" %>
<li>
<i class="material-icons">link</i>
<%= sermon_passage %> on Bible Gateway
</li>
<% end %>
<% end %>
<% end %>
<% end %>
</ul>

Related

Reduce code redundancy

I have a rails application which has some following code
<ul class="sortable grid row">
<% #videouploads.each do |video_upload| %>
<% if video_upload.category == 'モノナビ' && video_upload.priority == 1 %>
<%= render partial: 'adminrow', :locals => {:video_upload => video_upload } %>
<% end %>
<% end %>
</ul>
I have to write this code 10 times for video_upload.priority == 1 where priority changes from 1 to 10. How do I avoid code duplication or do I have what is the best solution ?
loop over the priorities
<% priorities = (1..10).to_a %>
<% priorities.each do |priority| %>
<ul class="sortable grid row">
<% #videouploads.each do |video_upload| %>
<% if video_upload.category == 'モノナビ' && video_upload.priority == priority %>
<%= render partial: 'adminrow', :locals => {:video_upload => video_upload } %>
<% end %>
<% end %>
</ul>
<% end %>
<% (1..10).each do |inc| %>
<ul class="sortable grid row">
<% #videouploads.each do |video_upload| %>
<% if video_upload.category == 'モノナビ' && video_upload.priority == inc %>
<%= render partial: 'adminrow', :locals => {:video_upload => video_upload } %>
<% end %>
<% end %>
</ul>
<% end %>
How about this ?

Separating posts in a newsfeed using CSS/BootStrap

I'm currently trying to render a newsfeed, similar to that of FB on a Rails application I'm working on. Unfortunately, I'm not the greatest when it comes to CSS and I'm having some issues trying to display different posts. This issue occurs whether I'm using BootStrap or plain CSS. I do believe it's something to do with the loop that is created by <% #posts.each do |post| %> Currently, whenever a new post is made, it wraps inside the previous post; thus the more posts that are made, the thicker the border gets.
Image:
<% if #posts.any? %>
<% #posts.each do |post| %>
<div class="well">
<%= post.user.first_name %> <%= post.user.last_name %><br>
<% if !post.image.exists? %>
<h2> <%= post.text %> </h2>
<% else %>
<h2> <%= link_to post.text, post_path(post) %> </h2>
<%= link_to post_path(post) do %>
<p><%= image_tag post.image.url(:medium) %></p>
<% end %>
<% end %>
<% if #user %>
<% if current_user.voted_up_on?(post) %>
<%= link_to "Like", dislike_post_path(post), method: :put %>
<% else %>
<%= link_to "Like", like_post_path(post), method: :put %>
<% end %>
<% end %>
<%= "Likes: #{post.get_upvotes.size}" %>
<% if post.user == current_user %>
<%= link_to "Edit", edit_post_path(post) %>
<%= link_to "Delete", post_path(post), method: :delete %>
<% end %>
<div id='comments_div' class="comments-index">
<%= render post.comments %>
</div>
<% if current_user %>
<%= form_for [post, post.comments.new ], remote: true do |f| %>
<%= f.text_area :text, placeholder: 'Add a comment' %>
<%= f.submit 'Comment' %>
<% end %>
<% else%>
<p>You need to <%= link_to "sign in", new_user_session_path %> to comment</p>
<% end %>
<% end %>
<% else %>
No posts have been added!
<% end %>
</div>
Any help would be greatly appreciated! Thanks.
Edit: OK, please take a look at the new image -- hopefully that will make the issue slightly more obvious. Additionally, I've removed all the dead tags and replaced them with just one: BootStrap's 'well' class. So, there you have it. All the information you need is within the code above.
from your description it sounds as though an html element is not being properly closed. Run the page source through an html validator and that could show you the problem.
If you don't want to take a structured problem solving approach, try adding another </div> to the end of your posts-index container.
Your issue is very simple, just that its not clear due to poor indendation.
A simple way to explain what you did is:
<-- if (start) -->
<-- do (start) -->
<-- post (start) -->
(post is not ending here, hence it breaks the layout)
<-- do (end) -->
<-- if (end) -->
<-- post (end) -->
Mistake in the above should be simple to understand so if you move your last </div>(of the well class) just before the second last <% end %>(of the <% #posts.each do |post| %> loop) it should fix the issue. So the last few lines should be
<% else%>
<p>You need to <%= link_to "sign in", new_user_session_path %> to comment</p>
<% end %>
</div>
<% end %>
<% else %>
No posts have been added!
<% end %>
Sounds to me like it could be a misplaced
<% end %>
or a missing
</div>
that is causing this behavior.
Proper indentation will point to where to close off actions or divs

How do I nest models using a form_tag in Rails 4?

I've got a form to add SaleQualifiers to my app - which works fine when I'm using:
<%= form_for(#sale_qualifier, :html => {role: :form, 'data-model' => 'sale_qualifier'}, remote: true) do |f| %>
The problem with form_for is that I want to put the form inline within a table row in my view - so as a method to get around that I'm now using:
<%= form_tag('/sale_qualifiers', method: :post, remote: true) do -%>
<%= fields_for :sale_qualifier do |ff| %>
This is working fine for most of the fields I need to generate, but I've got a nested attribute field for Answer (Answer belongs_to SaleQualifier). This is not generating the right field names in the view, and as a result when I go to save the object this way I don't capture the answer_attributes.
Here's the full working form using form_for:
<div class="panel panel-default">
<%= form_for(#sale_qualifier, :html => {role: :form, 'data-model' => 'sale_qualifier'}, remote: true) do |f| %>
<% if #sale_qualifier.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#sale_qualifier.errors.count, "error") %> prohibited this answer from being saved:</h2>
<ul>
<% #sale_qualifier.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="panel-body">
<div class="col-sm-6">
<h2><%= #question.question_text %></h2>
<% unless #question.id == 1 %>
<p><%= link_to('Back', edit_sale_qualifier_path(id: #prior_sale_qualifier), data: { disable_with: "Loading..." }, :remote => true) %></p>
<% end %>
</div>
<div class="col-sm-6">
<div class="form-group">
<%= f.hidden_field :sales_opportunity_id, :value => #sales_opportunity.id %>
</div>
<div class="form-group">
<%= f.hidden_field :question_id, :value => #question.id %>
</div>
<% unless #question.id == 1 %>
<div class="form-group">
<%= f.hidden_field :prior_question_id, :value => #prior_question_id %>
</div>
<% end %>
<%= f.fields_for :answer do |answer| %>
<div class="form-group">
<% if #question.answer_type == 'Text Field' %>
<%= answer.text_area :answer_text, :placeholder => "Enter your answer", :class => "form-control"%>
<% end %>
<% if #question.answer_type == 'Datetime' %>
<div class='input-group date' id='datetimepicker' data-date-format="YY.MM.DD">
<%= answer.text_field :answer_text, class: "form-control", data: { date_format: 'YYYY/MM/DD' }, :placeholder => "YYYY/MM/DD" %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<% end %>
<% if #question.answer_type == 'Boolean' %>
<%= answer.select :answer_text, [['Yes', true], ['No', false]] %>
<% end %>
<% if #question.answer_type == 'Update' || #question.answer_type == 'Result' %>
<%= answer.hidden_field :answer_text, :value => "Updated" %>
<% end %>
<span class="warning-block"></span>
<span class="help-block"></span>
</div>
<% end %>
<% if #question.answer_type == 'Update' || #question.answer_type == 'Result' %>
<div class="actions">
<%= f.submit "Done", class: "btn btn-large btn-success", data: { disable_with: "Submitting..." }, autocomplete: 'off' %>
</div>
<% else %>
<div class="actions">
<%= f.submit "Submit", class: "btn btn-large btn-success", data: { disable_with: "Submitting..." }, autocomplete: 'off' %>
</div>
<% end %>
<% end %>
</div>
</div>
</div>
Here's the code which does not work using form_tag:
<%= form_tag('/sale_qualifiers', method: :post, remote: true) do -%>
<%= fields_for :sale_qualifier do |ff| %>
<%= ff.hidden_field :sales_opportunity_id, :value => #sales_opportunity.id %>
<%= ff.hidden_field :question_id, :value => #question.id %>
<tr>
<td><%= #question.question_text %></td>
<td>
<%= ff.fields_for :answer do |answer| %>
<% if #question.answer_type == 'Text Field' %>
<%= answer.text_area :answer_text%>
<% end %>
<% if #question.answer_type == 'Datetime' %>
<div class='input-group date' id='datetimepicker' data-date-format="YY.MM.DD">
<%= answer.text_field :answer_text, class: "form-control", data: { date_format: 'YYYY/MM/DD' }, :placeholder => "YYYY/MM/DD" %>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<% end %>
<% if #question.answer_type == 'Boolean' %>
<%= answer.select :answer_text, [['Yes', true], ['No', false]] %>
<% end %>
<% end %>
</td>
<td>
<%= ff.submit "Submit", class: "btn btn-large btn-success", data: { disable_with: "Submitting..." }, autocomplete: 'off' %>
</td>
</tr>
<% end %>
<% end %>
For completeness, the issue I'm having is that the generated html for the working code creates the following field:
textarea id="sale_qualifier_answer_attributes_answer_text" name="sale_qualifier[answer_attributes][answer_text]"
The broken code creates the following html:
Textarea id="sale_qualifier_answer_answer_text" name="sale_qualifier[answer][answer_text]"
So how can I get the html output to show "sale_qualifier[answer_attributes][answer_text]" rather than "sale_qualifier[answer][answer_text]" in this instance using form_tag?
In multiple nested forms the fields_for tag will be called against
right parent and attributes conventions should be followed right otherwise
it renders the form attributes wrong and results in errors.
<%= form_tag('/sale_qualifiers', method: :post, remote: true) do -%>
<%= fields_for :sale_qualifier do |ff| %>
<%= ff.fields_for :answer_attributes do |answer| %>
Above flow will be the right one & will generate attributes as they should be.

Some HTML for values of Hash keys

I am building a panel with a partial, but I'd like to customise the inside of the panel with some html. Is there any way to write some HTML for a hash value?
I have a custom partial _panel_builder.html.erb that I takes as argument pclass, heading, body, etc., that I would like to use like this :
(The below syntax is bad, but I don't really understand how I could do something nice..)
<% #etudes.each_with_index do |etude, i| %>
<%= render 'shared/panel_builder',
pclass: panel_color_rotation(i),
heading: etude.name,
# For the body param, I'd like to be able to use some HTML with occasional <%=...%> for variables, like :
body: (%>
<p><%=etude.description %></p>
<ul>
<%etude.competences.each do |comp| %>
<li><strong><%= competence.name %></strong> : <%=competence.level %>
<br><small><%=competence.why %></small>
</li>
<% end %>
</ul>
<%).html_safe,
collapsable: true %>
<% end %>
EDIT : An idea of what my _panel_builder partial looks like :
<%
collapsable ||= false
pclass ||= "default"
footer ||= false
%>
<div class="panel panel-<%= pclass %> <%= if collapsable then "panel-collapsable " end %>">
<div class="panel-heading">
<%= heading %>
<% if collapsable %>
<span class="pull-right"><i class="glyphicon glyphicon-chevron-down"></i></span>
<% end %>
</div>
<div class="panel-body <%= if collapsable then "collapse" end %>">
<%= body %>
</div>
<% if footer %>
<div class="panel-footer <%= if collapsable then "collapse" end %>">
<%= footer %>
</div>
<% end %>
</div>
Okay so I was actually looking for the capture helper :
<% #etudes.each_with_index do |etude, i| %>
<%= render 'shared/panel_builder',
pclass: panel_color_rotation(i),
heading: etude.name,
body: capture do %>
<p><%=etude.description %></p>
<ul>
<%etude.competences.each do |comp| %>
<li><strong><%= competence.name %></strong> : <%=competence.level %>
<br><small><%=competence.why %></small>
</li>
<% end %>
</ul>
<% end %>,
collapsible: true %>
<% end %>
Note : in some cases, I also want to pass a complex HTML block as the header of footer, so I can't just have a helper that takes a block.
Note2 : My panel is a HTML template made for generic data. I cannot pass it a Ruby object

Link to Admin Dashboard in View

I already have Active Admin all set up and now I was trying to add a link to the dashboard in my view.
I have the current_admin_user method in my application_controller:
def current_admin_user
return nil if user_signed_in? && !current_user.admin?
current_user
end
And my view is:
<% if current_admin_user %>
<li><%= link_to "Admin", admin_path %></li>
<% end %>
However I'm getting the error:
undefined local variable or method `current_admin_user'
Anyone knows how to solve this?
If you want to use controller methods in views, you should add this line in your application_controller:
helper_method :current_admin_user
Put the function in your application_helpers.rb file in the /helpers folder instead and it should work
def current_admin_user
return nil if user_signed_in? && !current_user.admin?
current_user
end
An alternative is to use if user_signed_in? && current_user.admin? in your view
<% if user_signed_in? && current_user.admin? %>
<li><%= link_to "Admin", admins_path %></li>
<% end %>
This should work:
<% if user_signed_in? %>
<% if current_admin_user? %>
<li><%= link_to "Admin", admin_path %></li>
<% end %>
<% end %>
If it fails try:
<% if user_signed_in? %>
<% if current_user.admin? %>
<li><%= link_to "Admin", admin_path %></li>
<% end %>
<% end %>