How to do multiple where statements for the same column in ActiveRecord? - ruby-on-rails-3

Using rails 3, How could one do multiple where statements without complicated stuff or extra gems?
Im having this column "accepted" and would like to get all the values where accepted == false and accepted == null
Both of examples below fail:
#scholars = Scholars.where(:scholar_id => current_user.id).where(["accepted = ? or accepted = ?", true, null])
and
#scholars = Scholars.where(:scholar_id => current_user.id).where(:accpeted => true).where(:accepted=> null)

Try:
#scholars = Scholars.where(:scholar => current_user, :accepted => true).all +
Scholar.where(:scholar => current_user, :accepted => nil).all
Did you name your model "Scholars"? Models are traditionally singular... if you named it properly, this should be Scholar.where(...).

The correct answer should be
#profiles = Profile.where(:user_id => current_user.id, :accepted => [true, nil]).order(:accepted)

Related

Ruby on Rails 3 - retrieved data always zero

I can't find a working solution for the following piece of code:
def search_last_rate
self.rate = Rate.find(:first, :select => "rateconverted", :conditions => ["dominant_id = ? and converted_id = ?", self.currency_bought_iso, self.currency_sold_iso], :order => 'ratedate, dateloaded, timeloaded DESC')
end
When I execute this in the console I retrieve the appropriate value:
`=> #<Rate rateconverted: 0.8131>`
All columns are defined in MYSQL2 as an decimal but when I'm using it in the model and new html page it's always saving the value 0.0.
Please advice :)
decimal and integer are different in mysql. if u want the data to be numeric then use 'integer' in migrations else 'float'. checkout Decimal VS Int in MySQL?
Make sure that self.rate is not an integer
Try
self.rate = Rate.find(:first, :select => "rateconverted", :conditions => ["dominant_id = ? and converted_id = ?", self.currency_bought_iso, self.currency_sold_iso], :order => 'ratedate, dateloaded, timeloaded DESC').to_f

Rails 3 where with multiple params

I need to build a dynamic sql queue with 2 incoming params. It is easy when both params are defined.
MyClass.where(:column1 => param[:first], :column2 => params[:second])
but when for example param[:first] = 0 I want to select all(not null) fields for this column(so when both params are = 0 it would be equal to select * from tablename). Tried this syntax:
MyClass.where(:column1 => param[:first], :column2 => !nil)
but it gives me wrong output. Any suggestions how to elegantly resolve this?
You could use the ?: operator inside where:
MyClass.where(params[:first] ? {:column1 => params[:first]} : "column1 IS NOT NULL")
.where(params[:second] ? {:column2 => params[:second]} : "column2 IS NOT NULL")
What about MyClass.where('column1 IS NOT NULL AND column2 IS NOT NULL').where({:column1 => params[:first], :column2 => params[:second]}.delete_if{|k,v| v.nil?})?
I think this may work from what I've found. It appears to work in the rails console and considering active record alows active chaining:
MyClass.where(:column1 => params[:first], :column2 => params[:second]).where("column1 is NOT NULL").where("column2 is NOT NULL")

complex ActiveRecord to MongoID query

could you please help me to convert active record query to mongoid?
where(["access_grants.access_token = ?
AND (access_grants.access_token_expires_at IS NULL
OR access_grants.access_token_expires_at > ?)",
conditions[token_authentication_key], Time.now]).joins(:access_grants).
select("users.*").first
thank all, but i've got recipe how to solve this issue - http://groups.google.com/group/mongoid/browse_thread/thread/7d55c5687479355e
user_id = AccessGrant.where(:access_token => conditions[:token_authentication_key]).any_of({ :access_token_expires_at => nil }, { :access_token_expires_at.gt => Time.now).first.user_id
user = User.find(user_id)

conditional update_all with join tables in ActiveRecord?

The following query returns the collection of AR objects that I want to update:
Variant.all(:joins => { :candy_product => :candy }, :conditions => "candies.name = 'Skittles'")
I'm trying to do something like the following:
Variant.update_all(:price => 5, :joins => { :candy_product => :candy }, :conditions => "candies.name = 'Skittles'")
This should only update the price for the variants returned from original query. Is this possible with AR or will I have to write the SQL? This is a pretty large collection, so anything that iterates is out.
Using Rails 2.3.4.
As #François Beausoleil pointed correctly we should use scoped
Variant.scoped(:joins => { :candy_product => :candy }, :conditions => "candies.name = 'Skittles'").update_all(:price => 5)

Optimise ignoring of undefined variables when building find conditions in Rails

I have a an method that retrieves Groups that are present in certain areas. Groups are given a country_id, region_id and city_id
The UI gives three select boxes to choose a country, a region from that country and then a city from that region. To find all groups in a particular city, I have this code:
#groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
This all works fine, but I also want it to find all groups in an area when the lower criteria isn't specified. For example, If a country and region are given, but not city, I'd like to find it by the region.
What I'm doing is this:
if !params[:city_id].nil?
#groups = Group.find(:all, :conditions => {:city_id => params[:city_id]})
else
if !params[:region_id].nil?
#groups = Group.find(:all, :conditions => {:region_id => params[:region_id]})
else
#groups = Group.find(:all, :conditions => {:country_id => params[:country_id]})
end
end
This works perfectly well, but it seems like it's a little inefficient. Am I doing it the best way or can I streamline a little?
One idea I had was to have a single find checking against all parameters, but I could not work out how to effectively 'ignore' parameters that were nil - my main thought was to check which ones were not set and set them to something like '*' or 'true', but that's not how SQL plays the game.
Sounds like a job for named scopes:
class Group < ActiveRecord::Base
named_scope :in_city, lambda { |city_id| {
:conditions => { :city_id => city_id }
}}
named_scope :in_region, lambda { |region_id | {
:conditions => { :region_id => region_id }
}}
named_scope :in_country, lambda { |country_id | {
:conditions => { :country_id => country_id }
}}
end
This establishes some simple scopes for restricting the Group records. Presumably you have indexed your database properly so these are quick to resolve.
The controller is much easier to implement then:
def index
#group_scope = Group
if (!params[:city_id].blank?)
#group_scope = #group_scope.in_city(params[:city_id])
elsif (!params[:region_id].blank?)
#group_scope = #group_scope.in_region(params[:region_id])
elsif (!params[:country_id].blank?)
#group_scope = #group_scope.in_country(params[:country_id])
end
#groups = #group_scope.all
end
Generally you should be testing for .blank? instead of .nil? as some form elements can send in empty results, such as a select with something akin to "All" as the default.
You could use some Ruby idioms to get something a little more succinct.
Try something like this: (untested code!)
def index
#groups = Group.find :all, :conditions => [:city_id, :region_id, :country_id].inject {} do |conditions, name|
conditions[name] = params[name] unless params[name].blank?
conditions
end
end
If every value in params is a candidate for :conditions you can just do this:
#groups = Group.all(:conditions => params.reject { |idx, val| val.nil? })
This just throws out nil values from params and uses the remaining values for conditions.
If you don't want to use all of the values in params, you have two options. You can just get rid of a bunch of redundancy in your original code:
conditions = if !params[:city_id].nil?
{ :city_id => params[:city_id] }
elsif !params[:region_id].nil?
{ :region_id => params[:region_id] }
else
{ :country_id => params[:country_id] }
end
#groups = Group.all(:conditions => conditions)
You can knock of a few more lines like this, but it sacrifices a bit of readability IMO:
conditions = if !params[:city_id].nil? then { :city_id => params[:city_id] }
elsif !params[:region_id].nil? then { :region_id => params[:region_id] }
else { :country_id => params[:country_id] }
end
Or you can do something like this:
conditions = [:city_id, :region_id, :country_id].inject({}) do |hsh, sym|
hsh[sym] = params[sym] unless params[sym].nil?
hsh
end
#groups = Group.all(:conditions => conditions)
This has the advantage that you don't need to add another condition for each symbol.