RoR condition for collection - ruby-on-rails

i want to fetch other than collect value
i used below code
#boys = People.find(:all,:conditions => ["id != ?", #boy_id],:order => "created_at DESC")
where, #boy_id is collection of ids
but its not fetching the values
when i use IN(?) it fetches id in collection...
i want to fetch id values which are not in collection.. please suggest contrary to IN(?)

Have you tried
#boys = People.find(:all, :conditions => ["id NOT IN (?)", #boy_id], :order => "created_at DESC")

Related

Rails How to use join in this specific situation?

I have three models, each connected as such: Groups which has many Students which has many Absences.
Absences has a field called created_on.
I only have a group id and would like to obtain all students with an absence of today.
I have created this method inside my Student model:
# Inside student.rb
def self.absent_today_in_group (group)
#SQLITE
find(:all, :joins => :absences, :conditions => ["STRFTIME('%d', created_on) = ? AND STRFTIME('%m', created_on) = ?", Date.today.day, Date.today.month])
#POSTGRES
#find(:all, :joins => :absences, :conditions => ["EXTRACT(DAY FROM created_on) = ? AND EXTRACT(MONTH FROM created_on) = ?", Date.today.day, Date.today.month])
end
Why would that query not return anything? And how could I then also check for group_id?
What version of rails are you using? You can do this in rails 3:
def self.absent_today_in_group(group)
joins(:absences, :group).where(
'absences.created_on' => (Time.now.beginning_of_day..Time.now.end_of_day),
'groups.id' => group.id
)
end
That would find all users which were absent for today for given group.
Shouldnt this be :where and not :conditions?

Sorting a query on the sum of 2 columns

In rails 2.3.8 I'm trying to order a query having first the post that has the most comments AND votes.
I've tried to add a new method to the Post model as:
def interestingness
self.comments_count + self.votes_count
end
post_of_the_moment = find(:all, :conditions => ["submitted_at BETWEEN ? and ?", from, to],
:order => :interestingness,
:limit => 10
)
but this code gives me a Unknown column error.
I also tried this
post_of_the_moment = find(:all, :conditions => ["submitted_at BETWEEN ? and ?", from, to],
:order => "SUM(comments_count+votes_count) DESC",
:limit => 10
)
this doesn't give me errors but puts as result only 1 row that has 0 comments and 0 votes.
What am I doing wrong?
Thanks,
Augusto
Try this:
post_of_the_moment = find(:all, :select => '*, comments_count + votes_count AS total', :conditions => ["submitted_at BETWEEN ? and ?", from, to], :order => "total DESC", :limit => 10)
I'd also see if you can optimize it be replacing the * above with only the fields you actually need. Also check your MySQL indexes are ok, as you want to avoid a full table scan etc. to sum the counts.
Figured out the error I was doing: the SUM() in the order was grouping the result set.
This works:
post_of_the_moment = find(:all, :conditions => ["submitted_at BETWEEN ? and ?", from, to],
:order => "(comments_count+votes_count) DESC",
:limit => 10
)
Still don't know why I cannot use as a sort field the interestingness method I created.

when doing a ActiveRecord::Base count how do i order by count desc?

an example would be...
Pets.find(:all, :select => 'count(*) count, pet_type', :group => 'pet_type', :order => 'count')
returns the correct results but not the actual counts in the orderedhash object returned.
Pets.count(:all, :group => 'pet_type')
returns the count but are not sorting in a descending fashion... how would i do this?
I think i'd prefer to use .find .. but i'll take .count if i can sort it.
Pets.find(:all, :select => '*, count(*) AS count, pet_type', :group => 'pet_type', :order => 'count')
Pets.find(:all, :select => 'count(*) count, pet_type', :group => 'pet_type', :order => 'count DESC')
This works fine with MySQL but might not transfer well if you switch DBs:
Pets.count(:all, :group => 'pet_type', :order => 'count(*) DESC')
#pets=Pets.include(:meals_per_days).sort do |a,b|
a.meals_per_days.size <=> b.meals_per_days.size
end
Note : This will returns an array of records, not an ActiveRecord:Relation.
Note2 : Use size, not count, as count will execute sql calls to the db.

Multiple conditions with will_paginate

I am using will_paginate for pagination but I can't seem to use more than one condition at a time. For example, if I want to have a sql query that ends in "Where office_id = 5", then it's pretty straight forward, I can do that. but what if I want to do "Where office_id = 5 AND primary_first = 'Mark'"? I can't do that. I have no idea how to enter multiple conditions. Can you help??
Below is an example of my code:
def self.search(search, page, office_id)
paginate :per_page => 5, :page => page,
:conditions => ['office_id', "%#{office_id}"], # + ' and primary_first like ?', "%#{params[:search]}%"],
#:conditions => ['primary_first', "%#{search}%"],
:order => 'created_at'
end
Thank you for your help!
If I understand correctly what you want, this should work:
def self.search(search, page, office_id)
paginate :per_page => :page => page,
:conditions => ["office_id LIKE ? and primary_first LIKE ?", "%#{office_id}", "%#{search}%"]
:order => :created_at
end
try :conditions => ["office_id = ? and primary_first = ?", office_id, search]
or using a dynamic finder:
paginate_by_office_id_and_primary_first(office_id, search, :per_page => 5, :page => page, :order => 'created_at')
These will only work for equivalency, however the db is defining it. If you need to use LIKE, see Jens Fahnenbruck's answer

Rails: Sorting a query by params?

I am using running a simple find all and paginating with willpaginate, but I'd also like to have the query sorted by the user. The first solution that came to mind was just use a params[:sort]
http://localhost:3000/posts/?sort=created_at+DESC
#posts = Post.paginate :page => params[:page], :order => params[:sort]
But the problem with his approach is that the query is defaulting as sorting by ID and I want it to be created_at.
Is this a safe approach to sorting and is there a way to default to created_at?
I’d use a named scope for providing the default order (available since Rails 2.1).
You’d add the scope in your Post model:
named_scope :ordered, lambda {|*args| {:order => (args.first || 'created_at DESC')} }
Then you can call:
#posts = Post.ordered.paginate :page => params[:page]
The example above will use the default order from the named_scope (created_at DESC), but you can also provide a different one:
#posts = Post.ordered('title ASC').paginate :page => params[:page]
You could use that with Romulo’s suggestion:
sort_params = { "by_date" => "created_at", "by_name" => "name" }
#posts = Post.ordered(sort_params[params[:sort]]).paginate :page => params[:page]
If params[:sort] isn’t found in sort_params and returns nil then named_scope will fall back to using the default order.
Railscasts has some great info on named_scopes.
In general, the way to supply default values for Hash and Hash-like objects is to use fetch:
params.fetch(:sort){ :created_at }
A lot of people just use || though:
params[:sort] || :created_at
I prefer fetch myself as being more explicit, plus it doesn't break when false is a legitimate value.
The Ruby idiom to set a default would be:
#posts = Post.paginate :page => params[:page], :order => params[:sort] || "created_at"
But the approach isn't safe. The paginate method will not bother with a parameter like "created_at; DROP DATABASE mydatabase;". Instead, you could use a dictionary of valid sort parameters (untested):
sort_params = { "by_date" => "created_at", "by_name" => "name" }
#posts = Post.paginate :page => params[:page], :order => sort_params[params[:sort] || "by_date"]
So that the URI becomes:
http://localhost:3000/posts/?sort=by_date
I prefer this idiom:
#posts = Post.paginate :page=>page, :order=>order
...
def page
params[:page] || 1
end
def order
params[:order] || 'created_at ASC'
end

Resources