multiple conditions in ruby on rails - 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);'/>

Related

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.

How can I set a session variable from inside a monkeypath on String

I'm getting the following error...
pry("serp")> session[self.to_sym] = "closed"
NameError: undefined local variable or method `session' for "serp":String
...when I try to set a session variable from within a monkeypatch on the String class. (Necessary so I can track the progress of a job in delayed job in order to load my search results only when they are ready.)
How can I set a session variable there? Or is there a better solution?
My code...
/config/initializers/string.rb:
class String
def multisearch
result = PgSearch.multisearch(self)
session[self.to_sym] = "closed"
return result
end
end
/app/views/searches/show.html.haml:
- if #term.present? && session[#term.to_sym] == "open"
%h1 Search In Progress
# then show spinning wheel animation etc
- else
%h1 Search Results
= form_tag search_path, :method => :get do
= text_field_tag "term", "Search term"
= submit_tag "Search"
- unless #results.blank?
# then show the search results etc
**/app/views/layouts/application.html.haml:
!!!
%html
%head
- if #term.present? && session[#term.to_sym] == "open"
%meta{:content => "5", "http-equiv" => "refresh"}/
/app/controllers/searches_controller.rb:
class SearchesController < ApplicationController
respond_to :html
filter_access_to :all
def show
if #term = params[:term]
session[#term.to_sym] = "open"
#results = #term.delay.multisearch
# other stuff...
end
end
end
Pass the session as a parameter.
class String
def multisearch session
result = PgSearch.multisearch(self)
session[self.to_sym] = "closed"
return result
end
end
Then
#term.delay.multisearch(session)
The answer was to stop fighting Ruby's OO nature and to build a Search model that could own everything I needed to access.
/app/models/search.rb:
class Search < ActiveRecord::Base
serialize :results
def multisearch
results = PgSearch.multisearch(self.term).to_a
self.update_attributes :results => results, :status => "closed"
return results
end
end
** /app/controllers/searches_controller.rb**:
class SearchesController < ApplicationController
respond_to :html
def show
if params[:term].present?
#search = Search.find_or_create_by_term(params[:term])
if #search.status.blank?
#search.delay.multisearch
#search.status = "open"
#search.save
elsif #search.status == "closed"
#search.update_attributes :status => nil
end
end
end
end
/app/views/searches/show.html.haml:
- if #search.present? && #search.status == "open"
# progress bar etc
- else
= form_tag search_path, :method => :get do
= text_field_tag "term", "Search term"
= submit_tag "Search"
- if #search.present? && #search.status.nil?
- unless #search.results.blank?
# show the search results
/app/views/layouts/application.html.haml:
- if #search.present? && #search.status == "open"
%meta{:content => "5", "http-equiv" => "refresh"}/

collection_select NoMethodError - noticed after switching to rails 3.2.11

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.

form_for without ActiveRecord, form action not updating

I'm using an API instead of a database, so I'm not using ActiveRecord but ActiveModel (I mostly did like here: railscasts.com/episodes/219-active-model)
Thing is, when I try to edit an item (in my case a parking), the action of the form still remains the action of the create and not update.
so when I go on /parkings/2/edit to edit a parking, the form is still:
<form accept-charset="UTF-8" action="/parkings" class="form-horizontal" id="new_parking" method="post">
when it should be more like that with the put hidden field and the parkings/2 as the action:
<form accept-charset="UTF-8" action="/parkings/2" class="form-horizontal" id="edit_parking" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="_method" type="hidden" value="put" />
Anybody knows where the method & action of the form_for is set according to the route? What I'm trying to do is be as close as if I was using ActiveRecord with a database.
Here is some code :
_form.html.erb
<%= form_for(#parking, :html => { :class => "form-horizontal" }) do |f| %>
...
<% end %>
edit.html.erb & new.html.erb, simply has
<%= render 'form' %>
Controller
class ParkingsController < ApplicationController
def index
#parkings = Parse.get("Parking")
respond_to do |format|
format.html
format.json { render :json => #parking }
end
end
def new
#parking = Parking.new
respond_to do |format|
format.html
format.json { render :json => #parking }
end
end
def edit
#parking = Parking.find(params[:id])
respond_to do |format|
format.html
format.json { render :json => #parking }
end
end
def create
#parking = Parking.new(params[:parking])
if (#parking.save)
flash[:success] = "Parking was just added!"
redirect_to :action => "new"
else
render :action => "new"
end
end
def update
# Testing
parking = Parse.get("Parking", params[:id])
parking.delete("updatedAt")
parking["name"] = params[:parking][:name]
parking.save
redirect_to :action => "index"
end
Model
class Parking
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :name, :address, :city, :longitude, :latitude, :contributor_name, :contributor_email
validates_presence_of :name, :address, :city, :longitude, :latitude
#id = nil
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def self.find(id)
#id = id
raw = Parse.get("Parking", #id.to_s)
parking = Parking.new
parking.name = raw["name"]
parking.address = raw["address"]
parking.city = raw["city"]
parking.longitude = raw["location"]["longitude"]
parking.latitude = raw["location"]["latitude"]
parking.contributor_name = raw["contributorName"]
parking.contributor_email = raw["contributorEmail"]
return parking
end
def save
if (!valid?)
return false
else
parking = Parse::Object.new("Parking")
data =
{
:longitude => longitude.to_f,
:latitude => latitude.to_f
}
point = Parse::GeoPoint.new(data)
parking["location"] = point
parking["name"] = name
parking["address"] = address
parking["city"] = city
parking["contributorName"] = contributor_name
parking["contributorEmail"] = contributor_email
if (parking.save)
return true
end
end
end
def persisted?
false
end
end
Please note that the create is working and if I add the id of my parking in the form action="" using the Web Inspector or Firebug, and add :method => "put" in my form_for, my record successfully update.
The real problem here is really the form_for action & method who doesn't get updated when I'm editing a parking and remains like if I was adding a new one.
I'm still learning Rails, so sorry if some infos aren't clear!
Thank you!
--- SOLUTION ---
persisted? shouldn't only return false, and my model needed to define a method that returns the id of the object (so they can update the action="") so here's is my updated model:
class Parking
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :objectId, :name, :address, :city, :longitude, :latitude, :contributor_name, :contributor_email
validates_presence_of :name, :address, :city, :longitude, :latitude
#id = nil
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def self.find(id)
raw = Parse.get("Parking", id.to_s)
parking = Parking.new
parking.objectId = id
parking.name = raw["name"]
parking.address = raw["address"]
parking.city = raw["city"]
parking.longitude = raw["location"]["longitude"]
parking.latitude = raw["location"]["latitude"]
parking.contributor_name = raw["contributorName"]
parking.contributor_email = raw["contributorEmail"]
return parking
end
def save
if (!valid?)
return false
else
parking = Parse::Object.new("Parking")
data =
{
:longitude => longitude.to_f,
:latitude => latitude.to_f
}
point = Parse::GeoPoint.new(data)
parking["location"] = point
parking["name"] = name
parking["address"] = address
parking["city"] = city
parking["contributorName"] = contributor_name
parking["contributorEmail"] = contributor_email
if (parking.save)
return true
end
end
end
def update_attributes(aParking)
parking = Parse.get("Parking", #id.to_s)
parking.delete("updatedAt")
parking["name"] = aParking["name"]
parking.save
return true
end
def destroy
parking = Parse.get("Parking", #id)
#parking.parse_delete
end
def id
return self.objectId
end
def persisted?
!(self.id.nil?)
end
end
I think your problem is in your model's persisted? method. Since it always returns false, Rails always thinks it's building a form for a newly created record, so it uses POST and submits to the collection URL.
You need some sort of logic in that method so that existing records return true and new records return false.
Hi friend you can to tell the form builder which method to use.So try
<%= form_for(#parking, :method => ["new", "create"].include?(action_name) ? :post : :put,
:html => { :class => "form-horizontal" }) do |f| %>
...
<% end %>
If you are not using ActiveRecord you should use 'form_tag' instead 'form_for'

How can I make this code (helper) DRY in Rails where I am calling similar Models?

The end goal is to create a helper found at the end called show_status(contact,event).
Event can be any object, Email, Letter, etcetera. The combination of an Email template sent to a Contact is a specific record ContactEmail. Because each event has a different corresponding Model I need to do the .find on, I have duplication. There must be a better way!
def show_email_status(contact, email)
#contact_email = ContactEmail.find(:first, :conditions => {:contact_id => contact.id, :email_id => email.id })
if ! #contact_email.nil?
return #contact_email.status.to_s + " (" + #contact_email.date_sent.to_s + ")"
else
return "no status"
end
end
def show_call_status(contact, call)
#contact_call = ContactCall.find(:first, :conditions => {:contact_id => contact.id,
:call_id => call.id })
if ! #contact_call.nil?
return "sent " + #contact_call.date_sent.to_s(:long)
else
return "no status"
end
end
def show_letter_status(contact, letter)
#contact_letter = ContactLetter.find(:first, :conditions => {:contact_id => contact.id,
:letter_id => letter.id })
if ! #contact_letter.nil?
return "sent " + #contact_letter.date_sent.to_s(:long)
else
return "no status"
end
end
def show_voicemail_status(contact, voicemail)
#contact_event = ContactEvent.find(:first, :conditions => {:contact_id => contact.id,
:event_id => voicemail.id,
:type => "voicemail"})
if ! #contact_event.nil?
return "sent " + #contact_event.date_sent.to_s(:long)
else
return "no status"
end
end
def show_postalcard_status(contact, postalcard)
#contact_postalcard = ContactPostalcard.find(:first, :conditions => {:contact_id => contact.id,
:postalcard_id => postalcard.id })
if ! #contact_postalcard.nil?
return "sent " + #contact_postalcard.date_sent.to_s(:long)
else
return "no status"
end
end
def show_status(contact, call_or_email_or_letter_or_voicemail)
model_name = call_or_email_or_letter_or_voicemail.class.name.tableize.singularize
send "show_#{model_name}_status", contact, call_or_email_or_letter_or_voicemail
end
Try this:
def show_status(contact, target)
target_class= target.class.name
target_id = target_class.foreign_key.to_sym
klass = "Contact#{target_class}".constantize
r = klass.first(:conditions => {:contact_id => contact.id,
target_id => target.id})
return "no status" unless r
# If you want to treat ContactEmail differently then use the next line
#return "#{r.status} (#{r.date_sent})" if target.is_a?(ContactEmail)
"sent (#{r.date_sent.to_s(:long)})"
end
Usage:
contact = Contact.find(..)
email = Email.find(..)
letter = Letter.find(..)
call = Call.find(..)
show_status(contact, email)
show_status(contact, letter)
show_status(contact, call)
Edit 1
A better approach is to add a method to the Contact model.
class Contact < ActiveRecord::Base
# assuming you have following associations
has_many :contact_emails
has_many :contact_calls
has_many :contact_letters
# etc..
def communication_status target
target_class= target.class.name
target_id = target_class.foreign_key.to_sym
assoc_name = "contact_#{target_class.tableize}"
r = send(assoc_name).send("find_by_#{target_id}", target.id)
return "no status" unless r
"sent (#{r.date_sent.to_s(:long)})"
end
end
Usage:
contact = Contact.find(..)
email = Email.find(..)
letter = Letter.find(..)
call = Call.find(..)
contact.communication_status(email)
contact.communication_status(email)
contact.communication_status(letter)
contact.communication_status(call)
Combine all those models into one and then have an attribute that defines the type of media such as email, phone, paper, etc instead of having a different model for each type.
Then you can pass the object which will have a media type as the only parameter and with that object you can access the contact with media_object.contact and the media_type with media_object.media_type which you can use to search for the user and the type of media.
def show_media_object(mo)
options = {conditions = ['media_type = ? AND contact_id = ?',
mo.media_type, mo.contact_id]}
if #media_type = MediaObject.find(:first, options)
"sent " + #mo.updated_at
else
"Sorry, your SOL"
end
end

Resources