Conditionally add class to link_to with slim syntax - ruby-on-rails

I have a link and the code is as follows:
= link_to 'Payment', account_payment_path, class:{'active'}
and I want to add a conditional logic to the view, so if the action_name is same, then add class active
I then change to the following code
= link_to 'Payment', account_payment_path, class:{'active' if action_name == 'payment'}
but it results in error. How can I fix it.?

If you want to get active links there is a gem build for that active_link_to, you can use it like this and it will handle adding the active class for you:
=active_link_to 'Payment', account_payment_path
for your problem you can use this:
= link_to 'Payment', account_payment_path, class: (action_name == 'payment' ? 'active' : '')

Try this ......
= link_to 'Payment', account_payment_path, :class => action_name == 'payment' ? 'active' : ''
Hope this will help you.

I'm late to the party, but here's what I think is more flexible, i.e. can use with any HTML tag whether it be a, li or anything.
# app/helpers/menu_helper.rb
module MenuHelper
class MenuBuilder
def initialize(template, active_class_name, active_value)
#template = template
#active_class_name = active_class_name
#active_valule = active_value
end
def item(value)
contents = #template.capture { yield }
return contents unless value == #active_value
body = Nokogiri::HTML.parse(contents).at('body')
# Method :+= does not always work because body.child['class'] could be nil
body.child['class'] = "#{body.child['class']} #{#active_class_name}"
body.inner_html.html_safe
end
end
def menu_for(active_class_name, active_value)
capture { yield MenuBuilder.new(self, active_class_name, active_value) }
end
end
Rails loads this helper automatically so that you can use it in views:
# app/views/shared/_left_sidebar.html.slim
aside
.menu
ul.list
= menu_for 'active', yield(:sidebar_menu_l1_active_value) do |m|
= m.item 'menu-1'
li = link_to 'Menu 1', '#'
= m.item 'menu-2'
li = link_to 'Menu 2', '#'
-
# app/views/home/index.html.slim
- content_for :sidebar_menu_l1_active_value, 'menu-1'
...

Related

HAML class string with class based on if statement

I have this HAML code adding an "active" class based on an if statement.
= link_to 'Contact Information',
edit_account_path(:contact_information),
class: ("active" if params[:section] == 'contact_information')
I want to also add a string of classes permanently, outside of the if statement.
Something like
= link_to 'Contact Information',
edit_account_path(:contact_information),
class: "Tab large", ("active" if params[:section] == 'contact_information')
I need to do this without creating a helper method because I'm not allowed to edit the code too much.
Use the ternary operator:
= link_to 'Contact Information',
edit_account_path(:contact_information),
class: "Tab large #{params[:section] == 'contact_information' ? 'active' : ''}"
The second example:
= link_to 'Contact Information',
edit_account_path(:contact_information),
class: current_page?(edit_user_registration_path) ? 'active' : ''
create a helper method say find_classes,
def find_classes(section)
default_class = ['Tab Large']
if section == 'contact_information'
default_class << 'active'
end
default_class.join(' ')
end
and from your view,
class: find_classes(params[:section])
Advantage:
you can have multiple if's and can have various classes appended.

Rails: understanding custom form helper

new.html.erb
<%= form_for #star do |f|%>
<%= star_radio(f, true)%>
<% end %>
stars_helper.rb
module StarHelper
def star_radio(form, status)
form.label "star_#{status}", class: 'radio-inline' do
form.radio_button(:star, status) + i18n_star(status)
end
end
def i18n_star (status)
I18n.t("activerecord.attributes.star.is_sun.#{status}")
end
end
I saw a piece of code like above.
I am not familiar with custom form helper.
Could you let me know why we can use form.radio_button(:star, status) + i18n_star(status) inside a block and why we can use '+' to add text on radio buttons.
I will be appreciated if you could tell me where I can go to learn this.
form.radio_button helper returns a string and I18n.t too returns a string. So, you can concatenate them.
More details how form tag is generated
This is a code of radio_button:
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/form_helper.rb
def radio_button(object_name, method, tag_value, options = {})
Tags::RadioButton.new(object_name, method, self, tag_value, options).render
end
Look at implementation of render method
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/tags/radio_button.rb#L20
def render
options = #options.stringify_keys
options["type"] = "radio"
options["value"] = #tag_value
options["checked"] = "checked" if input_checked?(object, options)
add_default_name_and_id_for_value(#tag_value, options)
tag("input", options)
end
Tag helper generate html tag and return his as html safed string:
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/tag_helper.rb#L67
def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end

Rails, using scopes to filter table

i am fairly new to rails and i have to update an existing project. I have an existing database, beforehand it was just one User group, now there should be multiple. Now i want to use the old view, but filter with the help of a dropdown menu, but for some reason i can't work out what i am doing wrong.
Here are the code snippets i changed, since it was working beforehand, i assume my mistake must be somewhere within these lines.
event.rb
scope :men, lambda { { :conditions => ["team_id == ?", 1] } }
scope :women, lambda { { :conditions => ["team_id == ?", 2] } }
scope :juniors, lambda { { :conditions => ["team_id == ?", 3] } }
events_controller.rb
def index
# #events = Event.where("startdate >= ?", Date.today).order("startdate, starttime")
# #events = Event.order("startdate, starttime")
if params[:search]
#events = Event.search(params[:search])
else
if params[:filter].nil?
#events = Event.all
else
if params[:filter] == "Alle" then #events = Event.all end
if params[:filter] == "Men" then #events = Event.men end
if params[:filter] == "Women" then #events = Event.women end
if params[:filter] == "Juniors" then #events = Event.juniors end
end
end
end
and the index.html.erb
<div class="left">
<%= form_tag events_path, :method => 'get' do %>
<%= select_tag "filter", options_for_select([ "Alle", "Men", "Women", "Juniors" ], params[:filter]), {:onchange => 'this.form.submit()'} %>
<% end %>
probably it is a simple mistake. My guess is, that in the index.html.erb i am doing something wrong.
as a follow up, i want to filter just the events which are upcoming, for that i can use the commented part in the controller. can i just add that to the assignmnet in the style of:
#events = Event.men.where("startdate >= ?", Date.today).order("startdate, starttime")
thanks for the help
Lenny
You should change your scopes to new syntax:
scope :men, -> { where(team_id: 1) }
scope :women, -> { where(team_id: 2) }
scope :juniors, -> { where(team_id: 3) }
Your controller logic is a little buggy and twisted (checking 5 times filter isnt best way, why checking e.g. if filter is "Men" if you already matched it with "Alle" ?). Here is some help:
#events = if params[:search].present?
Event.search(params[:search].to_s)
else
case params[:filter]
when "Men"
Event.men
when "Women"
Event.women
when "Juniors"
Event.juniors
else
Event.all
end
end
Speaking about view, you shouldnt use inline js, just because its XXI century, and such "quick solutions" are harder to maintain later, so:
<div class="left">
<%= form_tag events_path, :method => 'get' do %>
<%= select_tag "filter", options_for_select([ "Alle", "Men", "Women", "Juniors" ], params[:filter]), class: 'my_filter' %>
<% end %>
and then add to your events.coffee:
$('select.my_filter').on 'change', ->
$(this).parents('form').submit()
Hope this helps!

Passing params in a helper

I have, on my Miniature model view page the following code
<%= content_setmini_links_with_quantity(#miniature) %>
It refers to this miniatures_helper method
def content_setmini_links_with_quantity(miniature)
miniature.reverse_contents.map{|content| content_setmini_link_with_quantity(content)}.join(' ').html_safe
end
Which in turn references this miniatures_helper method
def content_setmini_link_with_quantity(content)
string = (tag "td"), (link_to top_pic(content.setmini_id), content.setmini), (link_to content.setmini.name, content.setmini)
string << " x#{content.quantity}" if content.quantity.present?
return string
end
This is supposed to reference the final miniatures_helper method
def top_pic
#miniature = Miniature.find(params[:setmini_id])
if #miniature.collections.first.photo != nil
image_tag(#miniature.collections.first.photo.url(:icon), :retina => true, :class => "curvediconminiset")
else
image_tag("https://system/stock/blank.gif", :retina => true, :class => "curvediconminiset")
end
end
but I can't work out how to call top_pic correctly.
As far as I can see in content_setmini_link_with_quantity(content) the only param available is content. Content.setmini_id is the param I want to use to find the #miniature to display but I can't get it to work.
Any help much appreciated.
You are calling
top_pic(content.setmini_id)
But your top_pic method definition does not have a parameter defined.
Change the definition and first line of top_pic to
def top_pic(setmini_id)
#miniature = Miniature.find(setmini_id)
and forget about using params in a helper.

Method to return multiple bits of text Rails

I am currrently in the process of writing a new rails application and have a div near the top of my page called background that contains an image, a Title and some sub title text.
At the moment I have created seperate helper methods, as below, that passes in each of the elements by testing against the action and controller parameter.
This doesn't however seem like a very efficient way of implementing the code and so I was wondering what would be the best way to pass the three elements together in one method?
Currently I have a setup like this:
def background
if params[:action] == "index" && params[:controller] == "everydays"
return "/assets/everyday.jpg"
elsif params[:action] == "index" && params[:controller] == "mens"
return "/assets/mens.jpg"
elsif params[:action] == "index" && params[:controller] == "womens"
return "/assets/womens.jpg"
end
end
def title_h1
if params[:action] == "index" && params[:controller] == "everydays"
return "Everyday"
elsif params[:action] == "index" && params[:controller] == "mens"
return "Mens"
elsif params[:action] == "index" && params[:controller] == "womens"
return "Womens"
end
end
def title_h3
if params[:action] == "index" && params[:controller] == "everyday"
return "Example text for this Everyday Section"
elsif params[:action] == "index" && params[:controller] == "mens"
return "Example text for this Mens Section"
elsif params[:action] == "index" && params[:controller] == "womens"
return "Example text for this Womens Section"
end
end
Any advice people can offer would be much appreciated.
You're right to be suspicious, that is a terrible code smell, and has surprisingly spilled over into the answers! I'll try to bring a little sanity to this page.
Use content blocks for your page-specific background image
# views/layouts/application
<% if content_for?(:background_image) %>
<%= yield(:background_image) %>
<% else %>
<img src="default" />
<% end %>
# views/everydays/index
<% content_for :background_image %>
<img src="/assets/everyday.jpg" />
<% end %>
Use locale files for page-specific text
# locales/en.yml
everydays:
index:
title_h1: 'Everyday'
title_h3: 'Example text for this Everyday Section'
# views/everydays/index
<h1><%= t('everydays.index.title_h1') %></h1>
If the h1 tag is not within your index templates, as in, is a site-wide tag within your application template, then you can use code blocks as described above, or you could create a helper which fetches the relevant title based on the controller:
# application_helper.rb
def title(tag)
t("#{params[:controller]}.#{params[:action]}.title_#{tag}")
end
# usage
<h1><%= title('h1') %></h1>
As you can see, there are many ways to approach this, and even improve on the above.
I would start working with hashes as it eliminates the many tests the if clauses are doing (so the following would all be helper methods):
def fragments
return {
"everydays#index" => {
:background => "/assets/everyday.jpg",
:title => "Everyday",
:description => "Example text for this Everyday Section"
},
"mens#index" => {
...
}
...
}
end
def fragment_for(segment)
fragment = fragments["#{params[:controller]}##{params[:action]}"]
fragment ? fragment[section] : nil
end
You can then put into your views:
<%= fragment_for :background %>
or
<%= fragment_for :title %>
etc.
BTW, plural of "man" is "men" and plural of "woman" is "women".
You can have more than one return value in a method, like so:
def my_helper
if action == 'something'
return 'first return', 'second return', 'third return'
else
return 'first return 2', 'second return 2', 'third return 2'
end
end
You can then call this method:
first_value, second_value, third_value = my_helper
<%= first_value %>
<%= second_value %>
<%= third_value %>
You can just use a single method (say for ex : get_css_attribute_values) and return a hash where the key is name of the CSS attribute and the value is the string which you want to pass.
def get_css_attribute_values
if params[:action] == 'index' && params[:controller] == 'everydays'
return {:background_image => '/assets/everyday.jpg', :title_h1 => 'Everyday', :title_h3 => 'Example text for this Everyday Section' }
elsif params[:action] == 'index' && params[:controller] == 'mens'
return {:background_image => '/assets/mens.jpg', :title_h1 => 'Mens', :title_h3 => 'Example text for this Mens Section'}
elsif params[:action] == 'index' && params[:controller] == 'womens'
return {:background_image => '/assets/womens.jpg', :title_h1 => 'Womens', :title_h3 => 'Example text for this Womens Section'}
end
end
Then you can access all these attributes in the view as :
get_css_attribute_values[:background_image]
get_css_attribute_values[:title_h1]
get_css_attribute_values[:title_h3]

Resources