Sometimes in my Rails views, I have some duplicated code, because I have to set the parameters of a Rails helper method according to some conditions. Like:
<% if something %>
<%= link_to "Target", #target, class: "target-a" %>
<% else %>
<%= link_to "Target", #target, class: "target-b" %>
<% end %>
or another example:
<% if tooltip == false %>
<%= image_tag picture.url(size), class: "img-responsive #{css_class}" %>
<% else %>
<%= image_tag picture.url(size), class: "img-responsive #{css_class}", data: { toggle: "tooltip", placement: "bottom" }, title: "#{picture.name}" %>
<% end %>
Is there a way of writing this in a more elegant way (without repeating the whole helper)?
Thanks
You can isolate the differences in the options hash and merge just the differences into a shared base options hash:
<%
link_options =
if something
{}
else
{ data: { toggle: "tooltip", placement: "bottom" }, title: "#{picture.name}" }
end
%>
<%= image_tag picture.url(size),
link_options.merge(class: "img-responsive #{css_class}") %>
Or, better yet, you could do the same sort of thing but in your own, custom helper method. Using a helper method is preferable because then you have a method that can be tested, re-used, named (in a self-documenting manner), etc.
Related
First post on StackOverflow. :) Am new to Ruby on Rails (and coding in general), and I am struggling the most with understanding documentation. So I am sure this answer is out there somewhere, but if it is, I didn't find/understand it.
I am trying to create two options:
Click on logo before login- route to root_path
Click on logo after login- route to alerts_path
This solution below works, but there must be a better, more tidy and concise way to write it instead of repeating all of that code???
<% if user_signed_in? %>
<%= link_to alerts_path, class: "d-flex flex-row navbar-brand", input_html: {data: {bs_toggle: "offcanvas", bs_target: "#offcanvas"}} do %>
<%= cl_image_tag("ouicity_logo_j5rhro") %>
<h2 id="logo" class="ms-3">ouicity</h2>
<% end %>
<% else %>
<%= link_to root_path, class: "d-flex flex-row navbar-brand", input_html: {data: {bs_toggle: "offcanvas", bs_target: "#offcanvas"}} do %>
<%= cl_image_tag("ouicity_logo_j5rhro") %>
<h2 id="logo" class="ms-3">ouicity</h2>
<% end %>
<% end %>
A possible simple refactor (DRY code) is too just add logic for the url change (using the ternary operator):
<%= link_to user_signed_in? ? alerts_path : root_path, class: "d-flex flex-row navbar-brand", input_html: {data: {bs_toggle: "offcanvas", bs_target: "#offcanvas"}} do %>
<%= cl_image_tag("ouicity_logo_j5rhro") %>
<h2 id="logo" class="ms-3">ouicity</h2>
<% end %>
You can eventually extract this logic to a helper to keep your view simpler:
def logo_path
user_signed_in? ? alerts_path : root_path
end
<%= link_to logo_path, ...
I have a do statement in my view and was wondering how to format the code properly to use a class like other elements?
<%= link_to something_path do %>
<div>Stuff</div>
<% end %>
I tried to do it like most ERB, adding the class to the end of the statement:
<%= link_to something_path do, class: "classname" %>
That didn't work so I tried to do it like an image_tag:
<%= link_to(something_path do, class: "classname") %>
Where does class: fit into this line of code?
Try the following.
<%= link_to(something_path, class: "classname") do %>
<div>Stuff</div>
<% end %>
Check out the documentation for link_to
It also has this example,
link_to "Articles", articles_path, id: "news", class: "article"
# => Articles
I wish to add an export feature to the index views for several objects in my application. Index views all look the same, so they use partials.
Here is the index.html.erb for the Business Objects:
<% provide(:title, (t('ManagingBOs'))) %>
<%= will_paginate %>
<%= render partial: "shared/simple_export", locals: {this_path: business_objects_path} %>
<%= render partial: "shared/object_index", locals: {this_index: #business_objects} %>
<%= will_paginate %>
<br />
I would like the simple_export partial to define export links such as this, which works fine out of a partial:
Download:
<%= link_to "CSV", business_objects_path(format: "csv") %> |
<%= link_to "Excel", business_objects_path(format: "xls") %>
Unfortunately, the syntax <%= link_to "CSV", this_path(format: "csv") %> raises an Undefined method error.
How can I implement this partial ?
When you do:
locals: {this_path: business_objects_path}
You are not passing the method business_objects_path. You're calling the method business_objects_path and passing the resulting string to the partial. Remember that parens are optional for method calls in Ruby.
If you want to pass a method in Ruby (a function reference) you use the method method:
locals: {this_path: self.method(:business_objects_path) }
However you can just use the polymorphic routes helpers to lookup the method instead.
<%= render partial: "shared/simple_export", resource_name: :business_objects %>
Download:
<%= link_to "CSV", polymorphic_path(resource_name, format: "csv") %> |
<%= link_to "Excel", polymorphic_path(resource_name, format: "xls") %>
<%= link_to "CSV", url_for(:format => 'csv') %> |
<%= link_to "Excel", url_for(:format => 'xls') %>
WARNING : This version would also work, but could be potentially dangerous
<%= link_to "CSV", params.merge(:format => 'csv') %> |
<%= link_to "Excel", params.merge(:format => 'xls') %>
Should work fine, anywhere in your views, without having to use any extra variable.
I found many posts with this problem, but it's seems like none of them solves my problem. I got this code which i want to render from string:
<%= button_to "/admin/#{contr_name}/#{obj.id}", method: :delete, class: 'btn btn-danger btn-resource-destroy', data: {toggle: 'tooltip'}, title: 'Delete' do %>
<%= icon('trash-o') %> <span class='sr-only'>Delete</span>
<% end %>
I have tried this:
template += "<div class='col-sm-4'>"
template += "<%= button_to \"/admin/#{contr_name}/#{obj.id}\", method: :delete, class: 'btn btn-danger btn-resource-destroy', data: {toggle: 'tooltip'}, title: 'Delete' do %>
<%= icon('trash-o') %> <span class='sr-only'>Delete</span>
<% end %>"
template += "</div>"
ERB.new(template).result(binding)
but i get syntax errors.
How i can fix this?
I would suggest to use partials instead.
First, define the partial at, for example, views/shared/_delete_button.html.erb:
<%= button_to "/admin/#{contr_name}/#{obj.id}", method: :delete, class: 'btn btn-danger btn-resource-destroy', data: {toggle: 'tooltip'}, title: 'Delete' do %>
<%= icon('trash-o') %> <span class='sr-only'>Delete</span>
<% end %>
Then, you can render the partial with the wanted parameters:
render 'shared/delete_button', contr_name: [contr_name], obj: [obj]
Replacing [contr_name] and [obj] with whatever you want those variables to be assigned to.
Or, even better, allow the partial to extract the controller's name from predefined variables, like this:
<%= button_to "/admin/#{controller.controller_name}/#{obj.id}", method: :delete, class: 'btn btn-danger btn-resource-destroy', data: {toggle: 'tooltip'}, title: 'Delete' do %>
<%= icon('trash-o') %> <span class='sr-only'>Delete</span>
<% end %>
Now you only need to supply the obj when rendering it.
render 'shared/delete_button', obj: [obj]
You could also use named routes, and do [route_name]_path(obj) instead of manually constructing the path.
helpers/subcategories_helper.rb:
module SubcategoriesHelper
def has_topic_headings?
self.topic_headings
end
end
categories/show.html.erb contains
<% #category.subcategories.each do |subcategory| %>
<li>
<h6>
<%if subcategory.has_topic_headings? %>
<%= link_to subcategory.name, subcategory, data: :has_topic_headings %>
<% else %>
<%= link_to subcategory.name, subcategory %>
<% end %>
</h6>
<hr>
</li>
<% end %>
The page returns
undefined method `has_topic_headings?' for #<Subcategory:0xa68748c>
Please note that the view page belongs to the Category, not the Subcategory.
You are trying to call it on model which is why it is not called on when helper is included. Helpers are there for views and sometimes for controllers.
Here is your method :
<%= link_to subcategory.name, subcategory, data: :has_topic_headings %>
Edit: Sorry for misunderstanding. the error is in your data which you are passing in your link:
data: :has_topic_headings
rails is asking for above method, not for has_topic_headings?
Edit: Yes, as #techvineet said, you cannot call a helper method on a subcategory object.
you should write method in your subcategory model:
def has_topic_headings?
return true if self.topic_headings
end
Or you can do this in your helper class:
def has_topic_headings(subcategory)
return true if subcategory.topic_headings
end
and in your form, call it like this:
<%if has_topic_headings(subcategory) %>
<%= link_to subcategory.name, subcategory, data: :has_topic_headings %>
<% else %>
<%= link_to subcategory.name, subcategory %>
<% end %>
Hope it will help.Thanks