data attributes in li class? - ruby-on-rails

I have this code in my model:
def features_to_html_class
"mix #{bedrooms} #{region.name} #{categories.map{|cat|cat.name}.join(' ')}"
end
In my view this
- #regions.each do |region|
- #houses.where(region_id: region.id).each do |house|
%li{:class => house.features_to_html_class }
The HTML output is this:
<li class='mix 3 umbria price_range-1 villa_with_pool '>
This work fine but now i want to add data attributes "data-sort" and "data-order" to the li class. So i have this HTML output
<li class="mix 3 umbria price_range-1 villa_with_pool" data-sort="data-name" data-order="desc">
How must i change the features_to_html_class method to realize this?
Thanks...remco

To add new attributes in Haml you just have to pass them as hash ('attribute_name' => 'value')
Following should do
- #regions.each do |region|
- #houses.where(region_id: region.id).each do |house|
%li{:class => house.features_to_html_class, "data-sort" => "data-name", "data-order" => "desc"}
Edit:
Why your change in method 'features_to_html_class' can not be used in the view, because
you have directly written it class attributes(the value appended in the class of li element)
%li{:class => house.features_to_html_class }

This should work:
%li{class: house.features_to_html_class, data: {sort: 'data-name', order: 'desc'}}
Update
Since your data values are dynamic, you could change your method to provide the whole attributes hash:
def features_to_html_attributes
{
class: "mix #{bedrooms} #{region.name} #{categories.map{|cat|cat.name}.join(' ')}",
data: {sort: 'data-name', order: 'desc'}
}
end
And assign it via:
%li{features_to_html_attributes}

Related

Rails Locals - Passing Connected Model Data

My model structure is pretty solid. I have MarketingDeliverySystem has_many MarketingSections. MarketingSections has_many MarketingVideos.
I have another segment: GroupDevelopment has_many GroupSections. GroupSections has_many GroupVideos.
I'm trying to use a partial to pass the variables, thus DRYing it all up.
I have the following that I'm trying to pass to the partial:
= render partial: '/sales_presentations/sales_presentation',
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system}
Then in the partial I have the following:
.rounded-box-header.blue-bg #{sales_presentation.title}
ul
- sales_presentation.sections.ordered.each_with_index do |section, index|
- list_class = 'section show'
- list_class = 'section hide' if index != 0
li
= link_to section.title, '#', class: 'section', data: { id: section.id }
ul class="#{list_class}" data-section-id="#{section.id}"
- section.videos.ordered.each do |video|
li.video
= link_to video.title, '#',
class: 'video video-link',
data: { video: video.youtube_link,
sales_presentation: sales_presentation.title.parameterize }
.seven.columns
.row
div id="#{sales_presentation.title.parameterize}-container"
video {
id="#{sales_presentation.title.parameterize}-video-player"
class="video-js vjs-default-skin videos"
height=400
poster=""
controls preload='none'
data-default-url="#{first_video(sales_presentation)&.youtube_link}"
I previously had issues with sales_presentation.title at the top until I updated the locals.
My question/issue is how do I pass in through the locals to use for sales_presentation.sections instead to use #marketing_delivery_system.marketing.sections?
I thought I could just put that in through locals:
sales_presentation.sections: #marketing_delivery_system.marketing_sections but I end up with a massive syntax error.
I've also tried creating a partial view for these two and then changed sales_presentation throughout the view to mod. Then changed mod.sections to mod_section and setting that in the locals to mod_section: #marketing_delivery_system.marketing_section. The problem then gets into that I end up needing to hit video later in the iteration. So then that has the same issue.
You misunderstand the meaning of locals in partials.
Says we have
<%= render partial: 'image', locals: {size: #image.size, extension: #image.extension} %>
It means that in image partial now we can use local variable size and extension (keys) as #image.size and #image.extension (values).
Put in locals: {} all local variables you want.
So you can't write in locals sales_presentation.sections: #marketing_delivery_system.marketing.sections
But you can sales_presentation_sections: #marketing_delivery_system.marketing.section
Also you have problem with this code:
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system }
marketing_delivery_system and sales_presentation will be with the same value.

Conditionally add class to link_to with slim syntax

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'
...

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.

If params is present not working

My url paths are this
/locale/country/
/locale/country/region/
models:
class Region
belongs: country
end
class Country
has_many: regions
end
a foreign-key country_id in regions table
This is a part of a nav partial in the layout file.
//block region
- if params[:region].present?
%ul.thumbnails
- #region.tags.find_each(:conditions => "active_house = true") do |a|
%li.span2
.thumbnail
- a.attachments.limit(1).each do |b|
= image_tag(b.file.url)
.caption
%p
#{link_to a.h1, tag_country_region_houses_path(#country, #region, a.name), :class => 'btn-nav', class: active_class?(tag_houses_path(a.name))}
//block country
- else
%ul.thumbnails
- #country.tags.find_each(:conditions => "active_house = true") do |a|
%li.span2
.thumbnail
- a.attachments.limit(1).each do |b|
= image_tag(b.file.url)
.caption
%p
#{link_to a.h1, tag_country_houses_path(#country, a.name), :class => 'btn-nav', class: active_class?(tag_houses_path(a.name))}
When the visitor is on the path /local/country i want show block country and when the vistor is on /locale/country/region i want to show block region.
I thought if params[:region].present? will do the trick. But no....how can i realize this?
Before the line
- if params[:region].present?
In your view, try ptinting the lines,
- p params[:region]
- p params[:region].present?
that could give you some clue about the behaviour.
Try doing this:
if params.has_key?(:region)
or if it exists but contains a nil you could test it:
unless params[:region].nil?
Is it not supposed to be
class Region
belongs_to: country
end
instead of
class Region
belongs: country
end
Cheers

How can I collapse this very repetitive Ruby/Rails code?

I've got two small structural issues that I'm not sure how to handle given my relative newbie-ness with RoR.
First issue: In one of my views, I have code that looks like this:
<ul style="list-style-type: circle">
<li><%= #apples.size %> apples</li>
<li><%= #oranges.size %> oranges</li>
<li><%= #bananas.size %> bananas</li>
<li><%= #grapefruits.size %> grapefruits</li>
</ul>
Is it possible to refactor this so that I only need to iterate once over some list of different kinds of fruit, and have the appropriate <li>'s be automatically generated? Edit: I forgot to add that #apples, #oranges, etc., might be nil. Is there an idiomatic way to handle that?
Second issue: In my controller, I have code that looks like this:
#apples = Apple.find(:all)
#apples.each { |apple| apple.do_stuff(:xyz) }
#bananas = Banana.find(:all)
#bananas.each = { |banana| banana.do_stuff(:xyz) }
# ... &c
As you can see, the same operation is invoked many times in exactly the same way. Is there a way to shorten this to something like [Apple.find(:all), ...].each { |fruit| ... } and have that work instead?
Thanks very much for your help!
I'd do this in a helper
def fruit_size(fruit)
list = #fruits[fruit]
return if list.empty?
content_tag(:li, "#{list.size} #{fruit}")
end
And this in the view:
<% ["apples", "oranges", "bananas", .....].each do |fruit| %>
<%= fruit_size(fruit)
<% end %>
In your controller:
#fruits = {}
["apples", "oranges", "bananas", ......].each do |fruit|
#fruits[fruit] = fruit.classify.constantize.find(:all).each {|record|
record.whatever_here
end
end
It makes sense to store all the items in a hash, #fruits, so that you don't have to use instance_variable_get and stuff.
Perhaps you also want to define that array somewhere, so that you don't have to repeat it in the controller and in the view. Let's pretend that you have a fruit model.
class Fruit < ActiveRecord::Base
FRUITS = ["apples", "oranges", "bananas", ....]
end
Then, use Fruit::FRUITS in the view and controller.
For the first part:
#li = ''
[#apples, #oranges, #bananas, #grapefruit].each{|fruit|
#li << "<li>#{fruit.size}</li>"}
<ul style="list-style-type: circle">
<%=#li%>
</ul>
You can actually do it pretty simply.
In your controller:
def whatever
#fruits = {
:apples => Apple.find(:all).each{ |a| a.do_stuff(:xyz) },
:bananas => Banana.find(:all).each{ |a| a.do_stuff(:xyz) } # ...
}
end
In your view:
<% #fruits.each |k, v| %>
<li><%= v.nil? ? 0 : v.size %> <%= k.to_s %></li>
<% end %>
Although you might want to consider whether do_stuff is something that could be done via a more complex finder, or by named scope.

Resources