If params is present not working - ruby-on-rails

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

Related

Rails 4: How to put loop logic inside the controller

I have four loops in my haml document for testing purposes with the only difference being the order of the elements.
Am I somehow able to put the logic in my controller and list the whole 'insidyness' of the loop only once in my haml document?
Currently I have everything duplicated 4 times and ya know, that feels bad. :)
For instance:
- #loop.where(featured: true).order("RANDOM()").limit(4).each do |item|
%li
%h1 This is an example
- #loop.order(:cached_votes_up => :desc).limit(4).each do |item|
%li
%h1 This is an example
- #loop.order(:impressions_count => :desc).limit(4).each do |item|
%li
%h1 This is an example
- #loop.order("created_at DESC").limit(4).each do |item|
%li
%h1 This is an example
Controller:
def index
#loop = Item.all
end
I would like to reduce my Haml Code to something like this and move the rest in the Controller:
- #loop.each do |item|
%li
%h1 This is an example
Thanks in advance for each answer!
You can't render the view multiple times but you could do something like this.
def index
#loops = [
Item.where(featured: true).order("RANDOM()"),
Item.order(:cached_votes_up => :desc),
Item.order(:impressions_count => :desc),
Item.order("created_at DESC")
]
end
And then in the template
- #loops.each do |loop|
- loop.limit(4).each do |item|
%li
%h1 This is an example
in Item model class:
scope :featured_with_random_order_desc, ->(limit_value) { where(featured: true).order("RANDOM()").limit(limit_value) }
scope :by_cached_votes_order_desc, ->(limit_value) { order(:cached_votes_up => :desc).limit(limit_value) }
scope :by_impression_count_order_desc, ->(limit_value) { order(:impressions_count => :desc).limit(limit_value) }
scope :by_created_at_desc, ->(limit_value) { order("created_at DESC").limit(limit_value) }
In your views:
- #loop.featured_with_random_order_desc(4).each do |item|
%li
%h1 This is an example
- #loop.by_cached_votes_order_desc(4).each do |item|
%li
%h1 This is an example
- #loop.by_impression_count_order_desclimit(4).each do |item|
%li
%h1 This is an example
- #loop.by_created_at_desc.limit(4).each do |item|
%li
%h1 This is an example
You can go one more step further and create variable for each loop in your controller:
def index
#loop_featured = Item.featured_with_random_order_desc(4)
#loop_cached_votes = Item.by_cached_votes_order_desc(4)
#loop_impression_counts = Item.by_impression_count_order_desclimit(4)
#loop_by_created = Item.by_created_at_desc(4)
end
and use them in view:
- #loop_featured.each do |item|
%li
%h1 This is an example
- #loop_cached_votes.each do |item|
%li
%h1 This is an example
- #loop_impression_counts.each do |item|
%li
%h1 This is an example
- #loop_by_created.each do |item|
%li
%h1 This is an example
You can use union_scope from ActiveRecord
#item.rb
include ActiveRecord::UnionScope
scope :by_random, -> { where(featured: true).order("RANDOM()").limit(4) }
scope :by_cached_votes, ->{ order(:cached_votes_up => :desc).limit(4) }
scope :by_impression_count, ->{ order(:impressions_count => :desc).limit(4) }
scope :by_created_at, ->{ order("created_at DESC").limit(4) }
scope: all_conditions, -> { union_scope(by_random, by_cached_votes,by_impression_count,by_created_at}
your controller
#item = Item.all_conditions
your view:
- #loop.all_conditions.each do |item|

search items by category_id with select_tag drop down in rails

I have edited my first code and now it's better and cleaner thanks to #FunTimeFreddie, but the issue it's not yet properly solved. I'll come back with the right answer sooner.
In a search form I need to filter all menuitems:
1. per category
2. per category and search “query”
3. per min price && || max price
… and so on, with all possible combinations
I’ve manage to make a search in all menuitems with a “query”, min_price and max_price --all possible combinations from the search form. I can NOT manage to have the list of results of the chosen category, what am I doing wrong?
This is my model(edited):
class Menuitem < ActiveRecord::Base
belongs_to :menu_category
include Filterable
scope :newest_first, lambda { order('menuitems.created_at DESC') }
scope :last_one, lambda { order('menuitems.created_at ASC').last }
scope :search_keyword, lambda { |query|
where(["title LIKE ? or body LIKE ?", "%#{query}%", "%#{query}%"]) if query != ""
}
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id ) if menu_category_id != ""
}
scope :min_price, lambda { |price|
where("price > ?", price) if price != ""
}
scope :max_price, lambda { |price|
where("price < ?", price) if price != ""
}
end
This is my controller(edited):
class MenuitemsController < ApplicationController
def index
#menuitems = Menuitem.newest_first.filter(params.slice(:menu_category_id, :search_keyword, :min_price, :max_price))
end
And this is my view:
<%= simple_form_for :menuitem, :method => 'get', :url => {:action => 'index'} do |f| %>
<p>
<%= f.select :menu_category_id, options_for_select(#menucategories.map {|s| [s.title, s.id]}, params[:menu_category_id]), :selected => params[:menu_category_id], :onchange => "this.form.submit();", prompt: "Select category" %>
</p>
<p>
<%= f.input :search_keyword, input_html: { name: 'search_keyword', :value => params[:search_keyword]}, label: 'search recipe title', :required => false %>
<%= f.input :min_price, input_html: { name: 'min_price', :value => params[:min_price]}, label: 'min price:', :required => false %>
<%= f.input :max_price, input_html: { name: 'max_price', :value => params[:max_price]}, label: 'max price:', :required => false %>
<%= f.button :submit, "search" %>
</p>
<% end %>
You can save yourself the trouble of all the IF statements in your controller for all of the combinations by adding an IF statement within the scopes. For example, and this can similarly be applied to the four scopes associated to your form,
# menuitem model
scope :search_keyword, lambda { |query|
where(["name LIKE ?", "%#{query}%"]) if query != ""
}
This will allow to include only a single line in your controller, the line beneath your first IF statement, as this will handle the blank parameters.
There seems to be two issues with the category parameter. The first is it is a nested parameter within params[:menuitem], so in order to access it we need to call params[:menuitem][:menu_category_id]. Not too sure why this is happening to be honest, though I would recommend in this instance using a form_tag as opposed to form_for, given that we are not adding or editing the menuitems table itself.
The second issue is the category parameter is passed as a string, whereas we need it as an integer. We'll need to convert to parameter before applying it.
Now I'm not familiar with the .filters method (is this part of a gem?) but I got this to work the old fashioned way just by concatenating all the scopes together in one line as follows...
# menuitems controller
def index
#menuitems = Menuitem.newest_first.min_price(params[:min_price]).max_price(params[:max_price]).search_keyword(params[:search_keyword]).menu_category_id(params[:menuitem][:menu_category_id].to_i)
end
Note, another way of changing the data type would be to do so in the scope. You could do this as follows
# menuitem model
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id.to_i ) if menu_category_id != ""
}

data attributes in li class?

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}

belongs_to add a relationship?

these are my models
class Apartment
belongs_to :house
end
class House
has_many :apartments
end
apartment_controller;
def index
#apartments = Appartment.all
end
apartment index view
.span9
#container
- #appartments.each do |apartment|
.item{:class => apartment.features_to_html_class }
%article.info.t_xs
.article-base
%section
.span3
%h2 #{link_to apartment.name, appartment_path(apartment)}
%p
= raw truncate(apartment.property_description, :length => 375, :omission => '...')
%footer
%ul.meta
%li.comments
#{apartment.count_ratings}
= t('apartment.details.reviews')
%li.notes
#{apartment.guests}
= t('apartment.details.persons')
%li.notes
#{apartment.bedrooms}
= t('apartment.details.bedrooms')
%li.notes
#{apartment.bathrooms}
= t('apartment.details.bathrooms')
%ul.thumbnails
%li.span5
= image_tag(apartment.attachments.last.file.url, :class => 'thumbnail')
- apartment.attachments.limit(4).each do |a|
%li.span1
%a{:href => "#"}
= image_tag(a.file.url(:thumb), :class => "thumbnail")
.span8
%footer
#more
#{link_to t('apartments.summary.button'), appartment_path(apartment), :class => 'btn btn-primary'}
i get all the apartments from the DB. But now i want to add a link (belongs_to) to the house in at the apartment summary. how can i do this...thanks..remco
Did you try
link_to 'House', house_path(apartment.house) ?
Try this:
<%= link_to 'House', house_path(apartment.house) %>
or
<%= link_to 'House', house_url(apartment.house) %>
Regards!
You got all the apartments in the database.
Now you run the sql to get the apartments object.
Then iterate each apartment and link it to house with the association.
This is done as follows:
def index
#apartments = Appartment.all
#apartments.each do |apartment|
#this is giving you the link to house via association defined.
apartment.house
#this is giving you the value of the field say `house_name` of house table that is linked to apartment.
#house_name = apartment.house.house_name
.
.
.
end
end

Show only active (boolean) items in each loop

This is my loop. On my region page I show all the cities with there activities, events etc
- #cities.each do |city|
%li
%h4.h6.icon_mappoint
= link_to city.name, region_city_path(#region, city)
%ul
- city.events.each do |thing|
%li
= link_to event.name, region_city_event_path(#region, city, event)
%ul
- city.activities.each do |activity|
%li
= link_to activity.name, region_city_activity_path(#region, city, activity)
Each event and activity model has a attribute in the DB called active. (boolean). And want to show only the active events and activities in the view.
My controller looks like this now.
def show
#region = Region.find(params[:id])
#cities = #region.cities
end
Models
region has_many cities
city has_many events, activities
How can I show only the active events, activities in the each loop?
If you add a scope to your Event and Activity models
scope :active, where(:active => true)
you can write your views like
city.events.active.each do |thing|
and
city.activities.active.each do |activity|
Instead of city.events.each use city.events.select { |x| x.active }.each.

Resources