Conditionally add a class to link_to in Rails - ruby-on-rails

I want to conditionally add the class "hidden" to a Rails link tag, depending on if "accepted == true".
If I weren't using a rails link_to I could do <a href="#" class="foo bar <%= "hidden" if accepted == true %>" >. How can I accomplish this inside a link_to?
<%= link_to "Accept Friend Request",
"#",
class: "btn btn-success btn-sm btn-block requestSent ???hidden???",
disabled: true %>

If you use interpolation with #{}, anything you put between it is run as plain old Ruby code.
In this example you could add a conditional class in the string like this:
<%= link_to "Accept Friend Request",
"#",
class: "btn btn-success btn-sm btn-block requestSent #{'hidden' if accepted}",
disabled: true %>
Just note that you should use single quotes around the class name 'hidden'.
Also note that when a variable represents a boolean value (true or false), you don't need to explicitly say if accepted == true. You can simply say if accepted.

You can do it outside the link_to:
<% css_class = accepted ? "hidden" : "" %>
<%= link_to "Accept Friend Request",
"#",
class: "btn btn-success btn-sm btn-block requestSent #{css_class}",
disabled: true %>

You can use a helper to build up the link as well:
def accept_friend_request_link
classes = [:btn, :and_friends]
if accepted
classes << :hidden
end
link_to 'Accept Friend Request', '#', class: classes, disabled: true
end

I posted a similar answer to this question.
A cleaner solution
The standard approach requires putting logic into the views and using string interpolation or moving things into a separate helper.
Here's an updated approach that avoids any of that:
<%= link_to "Accept Friend Request",
"#",
class: class_string("btn btn-success btn-sm ban-block requestSent" => true, hidden: accepted),
disabled: true %>
class_string method
The class_string helper takes a hash with key/value pairs consisting of CSS class name strings and boolean values. The result of the method is a string of classes where the boolean value evaluated to true.
Sample Usage
class_names("foo bar" => true, baz: false, buzz: some_truthy_variable)
# => "foo bar baz"
Inspired by React
This technique is inspired by an add-on called classNames (formerly known as classSet) from Facebook’s React front-end framework.
Using in your Rails projects
As of now, the class_names function does not exist in Rails, but this article shows you how to add or implement it into your projects.

I've override the link_to to expect a class_if parameter, check it out:
def link_to(options = {}, html_options = {})
if html_options.is_a?(Hash) && html_options.key?(:class_if)
html_options[:class] <<
(" #{html_options[:class_if][1].strip}") if html_options[:class_if][0]
html_options.delete :class_if
end
super(options, html_options)
end
And usage:
<%= link_to(my_path, class: "class1", class_if: [true_or_false?, 'class2']) %>
I've just override one method, but a good refactor is to override all of described signatures here: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
UPDATE
Another solution is:
module ApplicationHelper
def active_link_to(name = nil, options = nil, html_options = nil, &block)
html_options ||= { class: '' }
html_options[:class].concat('is-active') if options.match(controller_name)
link_to(name, options, html_options, &block)
end
end
And usage:
<%= active_link_to(my_path, 'My path') %>
This way, I got an "active status" even when is a custom route like: "my_path/help", "my_path/two".

Related

Rails parameters contain backslashes

I am currently working with button_tag to create a remote styled answer submission quiz. When pressing this button, instead of posting the new record, it is throwing an error.
ActiveRecord::RecordNotFound (Couldn't find Answer without an ID):
When looking at the server logs I see it is trying to work with these params when trying to post Parameters: {"{\"answer_id\":59}"=>nil, "id"=>"15"}
What I am looking, or expecting to see is this.
Parameters: {"answer_id"=>"59", "id"=>"15"}
Here is the button_tag I am using.
<% #question.answers.each do |answer| %>
<%= button_tag "#{answer.answer.titleize}", class: 'btn btn-block btn-lg btn-primary', data: {
remote: true,
method: :post,
url: answer_question_path(#question),
params: { answer_id: answer.id }
} %>
<% end %>
Here is my response controller which is responsible for submitting the POST request.
class ResponsesController < ApplicationController
def answer
question = Question.find(params[:id])
answer = question.answers.find(params[:answer_id])
response = question.responses.find_or_initialize_by(user: current_user)
if response.update(answer: answer)
head :ok
else
puts 'Something went wrong chief'
end
end
private
def responses_params
params.require(:response).permit(:user_id, :question_id, :answer_id)
end
end
I have tried using to_json on the parameter with no success and have not been able to find any solution elsewhere on SO or other forums. Any ideas?
This seems to be an issue with button_tag in the feature I am using it for.
button_tag creates a button element that defines a submit button, resetbutton or a generic button which can be used in JavaScript. button_tag is also an action view helper but is defined as a FormTagHelper.
button_to generates a form containing a single button that submits to the URL created by the set of options. button_to is a UrlHelper while button_tag is a ViewHelper.
Below is the button_tag code I was using which was creating the issue described above. Using button_tag fixed my parameters issue and also looks a bit cleaner. I hope this helps anybody else having issues with button_tag in the future.
<%= button_tag "#{answer.answer.titleize}", class: 'btn btn-block btn-lg btn-primary', data: {
remote: true,
method: :post,
url: answer_question_path(#question),
params: { answer_id: answer.id }
} %>
<%= button_to "#{answer.answer.titleize}",
answer_question_path(#question),
class: 'btn btn-block btn-lg btn-primary',
params: { answer_id: answer.id },
remote: true %>

Rails helper method with link_to options as optionals

I'm trying to create a helper method that can have optional arguments for link_to method. My intention is to create a helper method for different cases:
# Typical case #1 (can have any number of extra arguments)
<%= toolbar_item('google.com', 'Google', 'globe', 'btn-primary', target: '_blank') %>
# Typical case #2 (extra arguments are optional)
<%= toolbar_item(root_path, 'Start', 'flag', 'btn-primary') %>
Follows the code:
def toolbar_item(url,text,icon,custom_class, optional_extra_settings = {})
link_to raw("<i class='fa fa-#{icon}'></i> #{text}"), url, class: custom_class, optional_extra_settings
end
It's no good. link_to method does not recognize the extra_settings and raises and error.
Any ideas?
Thanks!
The link_to method accepts only 3 arguments. The last argument needs to be a hash. Therefore you have to merge your class setting with the optional extra settings hash.
Change your example to:
def toolbar_item(url, text, icon, custom_class, optional_extra_settings = {})
html_options = { class: custom_class }.merge(optional_extra_settings)
link_to raw("<i class='fa fa-#{h icon}'></i> #{h text}"), url, html_options
end
Furthermore, you will notice that I used h to escape your icon and text. Just to be safe, because you disabled the auto-escaping that is usually done by Rails by using raw.
Don't reinvent the wheel. The CSS class is an option you can pass to the link_to helper via the options hash. Let's move it to the options hash and remove one needless argument.
# notice class: 'btn-primary' vs 'btn-primary'
<%= toolbar_item(..., class: 'btn-primary', target: '_blank') %>
Now, link_to also accepts a block. Use it to simplify your code pass the icon ('globe' or 'flag', etc...) as a block.
def toolbar_item(url, text, options = {}, &block)
if block_given?
link_to url, options do
yield
end
else
link_to text, url, options
end
end
Now, each time you use the helper with an icon, you can specify the icon you want:
<%= toolbar_item 'google.com', class: 'btn-primary' do %>
<%= content_tag :i, class: 'globe' %> Google
<% end %>
Which begs the question. Do you really need a helper after all? All we did was create a wrapper. You can just do:
<%= link_to 'Google', 'google.com', class: 'btn-primary' %>
<%= link_to 'Google', class: 'btn-primary' do %>
<%= content_tag :i, class: 'globe' %> Google
<% end %>

How to use HTML5 Entities in Rails 4 Helper Tags

I've been trying to use cdata_section, content_tag, escape_once and tag from the tag helper on rails to make the "X" appear from ✖
<%= link_to( ("✖"), url_options = {:base_rate_id => rates.id}, class: "button tiny" ) %
no luck with the different methods. it either displays nil or the raw literal "&#x2716"; is there better way?
Use ActionView::Helpers::SanitizeHelper
<%= link_to( sanitize("✖"), url_options = {:base_rate_id => rates.id}, class: "button tiny" ) %>
You just need to un-escape HTML entities as follow:
<%= link_to(CGI.unescapeHTML("✖"), url_options = {:base_rate_id => rates.id}, class: "button tiny" ) %>
P.S.: May be you need to include the CGI library:
require 'cgi'
You can use the following syntax
<%= link_to("✖".html_safe, url_options = {:base_rate_id => rates.id}, class: "button tiny") %>
However you should be careful using html_safe. Ensure that no user provided input makes its way into a string rendered using it.

Can't add class to Rails link_to

I tried to add a simple HTML class to my link_to tag:
<%= link_to "Individual Images", action: 'feature_highlights', site_title: site.title, class: "btn" %>
..but it gets appended to the URL instead:
How do I add a class to my link_to tag?
As per the API docs:
Be careful when using the older argument style, as an extra literal
hash is needed
So, the solution was
<%= link_to "Individual Images", { action: 'feature_highlights', site_title: site.title }, class: "btn" %>

Embed font-awesome icon in Rails button_to

I would like to have a button as follow:
[ Sign in with FB]
where FB is a font-awesome icon. I tried the following, but couldn't figure out how to embed the icon to the button:
= button_to "Login with", user_omniauth_authorize_path(:facebook)
Here is how font-awesome is normally invoked (in haml):
%i.icon-facebook-sign
How do I achieve the effect I want?
Thank you.
You can pass a block to button_to like so:
= button_to user_omniauth_authorize_path(:facebook) do
Login with
%i.icon-facebook-sign
(Though I'm not sure why you wouldn't just use the Facebook icon itself as the button.)
Add class option for button_to helper
= button_to "Login with", user_omniauth_authorize_path(:facebook), :class => 'icon-facebook-sign'
try this code, it runs for me
<%= button_to line_items_path(product_id: produit.id),class:"btn btn-outline-primary" do %>
<i class="fas fa-shopping-basket"></i>
<% end %>
just change the icon
You can create a helper method that uses the button tag but customizes the output:
#application_helper.rb
def button_to_with_icon(text, path, classes)
form_tag path, :method => :post do
button_tag(classes) do
raw text
end
end
end
Then call the helper method with the raw html embedded as an argument:
<%= button_to_with_icon("login with <i class='fa fa-facebook-official'></i>", { action: "omniauth_authorize", controller: "users" }, class: "btn btn-info") %>
The action, controller, and class settings are just examples. But you can modify this to suit your needs, I think.
Here's the helper I made that works for me:
def html_button_to(html = nil, options = nil, html_options = nil)
button_to(options, html_options) do
html
end
end
Combined with the font-awesome-rails gem, it lets you do:
html_button_to fa_icon(:facebook, text: "Login with"), user_omniauth_authorize_path(:facebook)

Resources