collection_select NoMethodError - noticed after switching to rails 3.2.11 - ruby-on-rails

After updating to rails 3.2.11, I noticed a problem with a search form in my app. After seeing the "We're sorry, but something went wrong." message on Heroku, I checked the logs and noticed the error message below:
NoMethodError (undefined method `to_i' for ["2010"]:Array):
app/controllers/skis_controller.rb:29:in `index'
This is referring to the index controller, where my search results are displayed. Im using a search form partial for the actual search form, which contains several collection_selects.
Line 29 in the index action refers to the model_year ("2010" in the search above). When I remove the model_year field from the collection_select everything works fine (no error message after searching). This is what the model_year collection_select looks like:
<%= collection_select(:ski, :model_year, #model_years.sort_by(&:model_year).reverse, :model_year, :model_year, {}, :multiple => true, :class => "chzn-select", :'data-placeholder' => "Enter Model Year") %>
This is bugging me because it has been working fine for the last three weeks. I recently updated to rails 3.2.11 but I'm not positive that is when the problem started (I know I did not notice it before). I checked out the collection_select documentation and everything seems fine.
model_year is stored in the database as an integer and I've confirmed this with rails console.
Any help or ideas would be very much appreciated! Thanks
EDIT - UPDATED to add controller code:
def index
#companies = Brand.scoped
#ski_types = Ski.find(:all, :select => "DISTINCT ski_type")
#genders = Ski.find(:all, :select => "DISTINCT gender")
#names = Ski.find(:all, :select => "DISTINCT name")
#price_ranges = PriceRange.scoped
#model_years = Ski.find(:all, :select => "DISTINCT model_year")
#sorts = ["Price", "Rating", "Availability"]
if params[:ski].present? || params[:brand].present? || params[:price_range].present?
# Creates references for collection select
ski_type = params[:ski][:ski_type].reject(&:blank?)
gender = params[:ski][:gender].reject(&:blank?)
company = params[:brand][:company].reject(&:blank?)
name = params[:ski][:name].reject(&:blank?)
price_range = params[:price_range][:price_range]
model_year = params[:ski][:model_year].reject(&:blank?)
# raise ski_type.any?.inspect
#ski = Ski.new
#ski.ski_type = ski_type
#ski.gender = gender
#ski.name = name
#ski.model_year = model_year
#price_range = PriceRange.new
#price_range.price_range = price_range
#brand = Brand.new
#brand.company = company
skis = Inventory.search_price(price_range)
skis_refined = Ski.search_characteristics(ski_type, gender, company, name, model_year)
ski_ids2 = skis.map(&:id) & skis_refined.map(&:id)
#all_skis = Ski.where(:id => ski_ids2)
if params[:sort_by] == "Price Low to High"
#overlapping_skis = Kaminari.paginate_array(#all_skis.joins(:inventories).order("inventories.price ASC").uniq_by(&:id)).page(params[:page]).per(30)
elsif params[:sort_by] == "Price High to Low"
#overlapping_skis = Kaminari.paginate_array(#all_skis.joins(:inventories).order("inventories.price DESC").uniq_by(&:id)).page(params[:page]).per(30)
elsif params[:sort_by] == "Rating"
#overlapping_skis = Kaminari.paginate_array(#all_skis.joins(:reviews).order("reviews.average_review DESC").uniq_by(&:id)).page(params[:page]).per(30)
else
#overlapping_skis = #all_skis.joins(:brand).order("brands.company ASC, skis.model_year DESC, skis.name ASC").page(params[:page])
end
else
#overlapping_skis = Ski.joins(:brand).order("brands.company ASC, skis.model_year DESC, skis.name ASC").page(params[:page])
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #skis }
end
end
Updated for search method:
def self.search_characteristics(ski_type, gender, company, name, model_year)
#skis = Ski.scoped
if ski_type.any?
#skis = #skis.where(:ski_type => ski_type)
end
if gender.any?
#skis = #skis.where(:gender => gender)
end
if company.any?
brand_object = Brand.where(:company => company)
#id_array = brand_object.map(&:id)
#skis = #skis.where(:brand_id => #id_array)
end
if name.any?
#skis = #skis.where(:name => name)
end
if model_year.any?
#skis = #skis.where(:model_year => model_year)
end
return #skis
end

You have :multiple => true, meaning there can be multiple selected values for model_year, which is why it's an array. You'll have to handle those multiple values some way or remove :multiple => true.

Related

multiple conditions in ruby on rails

I want to apply multiple conditions in ruby on rails app like below:
if !params[:parameters].blank? && params[:parameters] == "Designation"
puts "Hassan"
#dynamicDesignation = ""
#dynamicCompany = ""
#dynamicFrom = ""
#dynamicTo = ""
#Profession = Profession.new( :UserID => current_user.id, :Designation => #dynamicDesignation, :Company => #dynamicCompany, :Job_From => #dynamicFrom, :Job_To => #dynamicTo)
##Profession = #Profession.save
else
puts "Ali"
#dynamicDesignation = params[:parameters]
#dynamicCompany = params[:parametersCompany]
#dynamicFrom = params[:ParametersFromProf]
#dynamicTo = params[:ParametersToProf]
#Profession = Profession.new( :UserID => current_user.id, :Designation => #dynamicDesignation, :Company => #dynamicCompany, :Job_From => #dynamicFrom, :Job_To => #dynamicTo)
##Profession = #Profession.save
end
# redirect_to '/educations'
render 'index'
end
And parameters is dynamic control i.e below:
var input = "<input name='parameters' id='field' type='text' value='Designation' style='text-align:center;' onblur='WaterMarkDesignation(this, event);' onfocus='WaterMarkDesignation(this, event);'/>";
var input1 = "<input name='parametersCompany' id='field' type='text' value='Company' style='text-align:center;' onblur='WaterMarkCompany(this, event);' onfocus='WaterMarkCompany(this, event);'/>"
But its not going to the if condition, It only runs else condition, why. Kindly suggest me. Thanks
Firstly, if you're trying to ensure you don't get blank items saved into the DB, you should look at using nilify_blanks
I would do this:
#app/models/profession.rb
Class Profession < ActiveRecord::Base
nilify_blanks
end
#app/controllers/professions_controller.rb
def create
#Profession = Profession.new(profession_params)
#Profession.save
render 'index'
end
private
def profession_params
params.require(:profession).permit(:designation, :job_from, :job_to, :company).merge(userID: current_user.id)
end
Placeholder
Secondly, you're trying to prevent a placeholder (Designation) from being sent, instead of using value, why don't use placeholder
This will show the text you want, but will treat as blank unless it's been populated by the user:
<input name='parameters' id='field' type='text' placeholder='Designation' style='text-align:center;' onblur='WaterMarkDesignation(this, event);' onfocus='WaterMarkDesignation(this, event);'/>

Rails/MongoDb Search and Refine Search Implementation

I have a search functionality in my app which works as the following
Homepage: user selects location from a drop-down and then enters a search key-word and searches to get a set of results
Search Page (REfine Search Options): Once the user hits this page from the above he will be provided with more options to refine the search and narrow the results.
Right now we are implementing as follows but i am assuming as the paramenters increase over 5-7 the number of combinations will increase the number of if-else-elseif statement as well.
#refine search
#search = params[:search]
if params[:city].present? && params[:location_ids].present? && params[:search].blank?
#blood_banks = BloodBank.where(
{ :city_id => "#{#city}" }).where(
{ :location_id.in => params[:location_ids] })
elsif params[:search].present? && params[:location_ids].blank?
#blood_banks = BloodBank.where(
{ :bb_name => /##search/i })
elsif params[:search].present? && params[:city].present? && params[:location_ids].present?
#blood_banks = BloodBank.where(
{ :city_id => "#{#city}" }).where(
{ :location_id.in => params[:location_ids] }).where(
{ :bb_name => /##search/i })
end
Which is the best way to implement the same.
How do you achieve below code,
if params[:gender].present?
if params[:gender] == "male"
#doctors = Doctor.where( :gender => "Male")
end
if params[:gender] == "female"
#doctors = Doctor.where( :gender => "Female")
end
if params[:gender] == "any"
#doctors = Doctor.where( :gender => "Male") || Doctor.where( :gender => "Female")
end
end
Mongoid's where returns a Mongoid::Criteria and Mongoid::Criteria responds to where by returning another Mongoid::Criteria. This means that you can build your query piece by piece:
#blood_banks = BloodBank.all
if params[:city].present?
#blood_banks = #blood_banks.where(:city_id => params[:city])
end
if params[:location_ids].present?
#blood_banks = #blood_banks.where(:location_id.in => params[:location_ids])
end
...
As far as the second part goes, if you're searching for any gender then just leave it out entirely, then you can do things like:
#doctors = Doctor.all
genders = { 'male' => 'Male', 'female' => 'Female' }
if genders.has_key? params[:gender]
#doctors = #doctors.where(:gender => genders[params[:gender]]
end
Searching for any gender is the same not filtering on gender at all so the nil and 'all' cases are the same. Then you can handle the input and :gender values with a simple lookup table.

Cannot find by date

I am trying to get my app to pull all posts created on a specific date.
case meta_type
when "user"
#meta = User.find(params[:user_id])
#meta_title = #meta.username + "'s Posts"
#posts = Post.find(:all, :conditions => { :user_id => #meta.id})
when "category"
#meta = params[:category]
#meta_title = #meta + " Posts"
#posts = Post.find(:all, :conditions => { :category => #meta})
when "date"
#meta = Date.parse(params[:date])
#meta_title = #meta.strftime("%d/%m/%Y") + " Posts"
#posts = Post.find(:all, :conditions => { :created_at => #meta})
end
Here is my view:
- if #meta
%h2= #meta_title
- if #posts.count > 0
- #posts.each_slice(2) do |slice|
.row
- slice.each do |post|
.col-sm-6
.blog_entry
.img
%h3
%a= link_to post.title, posts_path + '/' + post.id.to_s
= render "blog_meta", :post => post
- else
%p= #user.username + " has no posts."
- else
%h2= "User does not exist."
I am getting undefined method 'username' for nil:NilClass which in itself isn't a problem, but the fact that it is getting filtered through to the else statement is, because it should be finding posts for that date.
Also I just realised by passing through the datetime, it will actually be looking for posts created at the exact same time, whereas I would like it to pull up all posts created on the day, not the time.
Any suggestions?
Thanks
So, ignoring the subtleties of exactly which time zone you're evaluating the date in, you can change your when "date" block to read as follows
#meta = Date.parse(params[:date])
#meta_title = #meta.strftime("%d/%m/%Y") + " Posts"
beginning_of_day = #meta.to_datetime.beginning_of_day
end_of_day = #meta.to_datetime.end_of_day
#posts = Post.where("created_at >= ?", beginning_of_day).where("created_at < ?", end_of_day).order(:created_at).all
That will give you a list of Posts created on the day in question, in the time zone in which your app is running, ordered by creation time.
You can make a number of other adjustments (changing sort order, using a different time zone, etc.) as needed.

Search ignoring certain blank parameters

I have a simple search action that has 3 parameters and a where method to search a model. If I search and some of the parameters are nil, it will not return the records I want. I want it to search the database by only using the parameters that are not nil/blank. So if only one category is entered and sent in the parameters, I want my controller to ignore the other two parameters. However, if the other parameters are present, I want them to be included in the search.
I've tried many approaches but I can't get it to work properly. Here's my code.
hash = []
cat = :category_id => params[:category_id]
col = :color_id => params[:color_id]
brand = :brand_id => params[:brand_id]
if params[:category_id].present?
hash += cat
end
if params[:color_id].present?
hash += col
end
if params[:brand_id].present?
hash += brand
end
#results = Piece.where(hash).preload(:item).preload(:user).group(:item_id).paginate(:page => params[:page], :per_page => 9)
I've put the variables into strings and hashs, called to_a, joined them with (","). Nothing works.
Thanks
Try this code.
criteria = { :category_id => params[:category_id], :color_id => params[:color_id],
:brand_id => params[:brand_id] }.select { |key,value| value.present? }
#results = Piece.where(criteria).preload(:item).preload(:user).group(:item_id).
paginate(:page => params[:page], :per_page => 9)

Remove a tag type from the view (involves alphabetical pagination)

I have an index view that lists all of the tags for my Entry and Message models. I would like to only show the tags for Entries in this view. I'm using acts-as-taggable-on.
Tags Controller:
def index
#letter = params[:letter].blank? ? 'a' : params[:letter]
#tagged_entries = Tagging.find_all_by_taggable_type('Entry').map(&:taggable)
#title = "Tags"
if params[:letter] == '#'
#data = Tag.find(#tagged_entries, :conditions => ["name REGEXP ?",
"^[^a-z]"], :order => 'name', :select => "id, name")
else
#data = Tag.find(#tagged_entries, :conditions => ["name LIKE ?",
"#{params[:letter]}%"], :order => 'name', :select => "id, name")
end
respond_to do |format|
flash[:notice] = 'We are currently in Beta. You may experience errors.'
format.html
end
end
tags#index:
<% #data.each do |t| %>
<div class="tag"><%= link_to t.name.titleize, tag_path(t) %></div>
<% end %>
I want to show only the taggable type 'Entry' in the view.
Any ideas? Thank you for reading my question.
SECOND EDIT:
Tags Controller:
def index
#title = "Tags"
#letter = params[:letter].blank? ? 'a' : params[:letter]
#taggings = Tagging.find_all_by_taggable_type('Entry', :include => [:tag, :taggable])
#tags = #taggings.map(&:tag).sort_by(&:name).uniq
#tagged_entries = #taggings.map(&:taggable)#.sort_by(&:id)#or whatever
if params[:letter] == '#'
#data = Tag.find(#tags, :conditions => ["name REGEXP ?",
"^[^a-z]"], :order => 'name', :select => "id, name")
else
#data = Tag.find(#tags, :conditions => ["name LIKE ?",
"#{params[:letter]}%"], :order => 'name', :select => "id, name")
end
respond_to do |format|
format.html
end
end
tags#index:
<% #data.each do |t| %>
<div class="tag"><%= link_to t.name.titleize, tag_path(t) %></div>
<% end %>
Max Williams' code works except when I click on my alphabetical pagination links. The error I'm getting [after I clicked on the G link of the alphabetical pagination] reads:
Couldn't find all Tags with IDs (77,130,115,...) AND (name LIKE 'G%') (found 9 results, but was looking for 129)
Can anyone point me in the right direction?
#taggings = Tagging.find_all_by_taggable_type('Entry', :include => [:tag, :taggable])
#tags = #taggings.map(&:tag).sort_by(&:name)
#tagged_entries = #taggings.map(&:taggable).sort_by(&:id)#or whatever

Resources