Using Paginate with constructed query in active record - ruby-on-rails

I'm trying to do something along the following lines:
if start_date?
query = where("datetime > :start_date", :start_date => start_date)
end
if end_date?
query = where("datetime <= :end_date", :end_date => end_date)
end
if client
query = where("client.name LIKE :client", :client => client)
end
if staff
query = where("staff.name LIKE :staff", :staff => staff)
end
paginate :per_page => 20, :page => page,
:conditions => query,
:order => 'datetime'
I can't find any examples though of how to build up a query and use it along with paginate plugin. Of course the query isn't correct yet as I've got to figure out how to do the joins so I can query against the other properties in other tables, but other than that, how do you build up queries to use in the conditions?

You want to put the .paginate call on the end of the chain of where calls, like this (all one line, split up for readability)
SomeClass.where("datetime > :start_date", :start_date=>start_date).
where("datetime < :end_date", :end_date=>end_date).
paginate(:per_page=>20,:page=>page)
If you want to conditionally add the conditions, you can do that too, like:
x = SomeClass
x = x.where("datetime > :start_date", :start_date=>start_date) if start_date
x = x.where("datetime < :end_date", :end_date=>end_date) if end_date
x.paginate(:per_page=>20,:page=>page)

You can try this if you installed kaminari gem :
ModelName.where( your_query ).page(params[:page]).per(50)

.where() returns ActiveRecord::Relation
.paginate()'s :conditions parameter has to be an array of conditions as if it was an argument of .where().
You should fix your code as next:
if start_date?
query = ["datetime > :start_date", :start_date => start_date]
end
etc.

ActiveRecord Relation doesn't have paginate method

Related

Activerecord syntax of where clause on joins

I want to select all Line items that have an order that has been created between two dates (order has the column date)
Here's what im trying to do
LineItem.where(:product_id => self.id).joins(:order).where(:orders => {"date > ? and date < ?", date_start, date_end}).all
I cant figure out the syntax of the last condition...
I know this kind of where do work:
.where("date > ? and date < ?", date_start, date_end)
and this kind of where too:
.where(:orders => {:id => 23043})
but how can i do a mix of the two kinds so i can get something like the first request?
Try this
.where(:date => date_start..date_end, :order => {:id => 23043})
You can just chain the clauses together and it will automatically join them with an AND:
.where("date > ? and date < ?", date_start, date_end).
where(:orders => {:id => 23043})

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?

RoR | how to find the next and previous based on a date

I'm trying to look up 1 instance of a model via a slug, which I can do via
#project = Project.where(:slug => params[:id]).first
But once I get the instance I want to find the next and previous instances of the model from a order of a column called publish which is a date.
how would I get the slug only of the previous and next instance of my arbitrary order by column?
::Edit::
Adding this to my modeled worked.
def previous(offset = 0)
self.class.select('slug').first(:conditions => ['published < ?', self.id], :limit => 1, :offset => offset, :order => "published DESC")
end
def next(offset = 0)
self.class.select('slug').first(:conditions => ['published > ?', self.id], :limit => 1, :offset => offset, :order => "published ASC")
end
I found this solution at Next, Previous Records Using Named Scope
Assuming your publish dates are unique something like this ought to work:
#project = Project.where(:slug => params[:id]).first
#prev_project = Project.where( "publish < ?", #project.publish ).
order( "publish DESC" ).
first
#next_project = Project.where( "publish > ?", #project.publish ).
order( "publish" ).
first
For #prev_project the where clause indicates all Projects before #project, the order lists them latest first (which puts the one right before #project at the top) and first limits the query to one result, i.e. the previous Project. The query for #next_project is the same but reversed. If publish isn't unique you'll have to sort on a second criterium as well.
However, you may want to consider not reinventing the wheel and using the very common gem acts_as_list, which would make this as simple as #project.higher_item and #project.lower_item.

Next, Previous Records Using Named Scope

I have a model for which I want to retrieve the next record(s) and previous record(s). I want to do this via a named_scope on the model, and also pass in as an argument the X number of next/previous records to return.
For example, let's say I have 5 records:
Record1
Record2
Record3
Record4
Record5
I want to be able to call Model.previous or Model.previous(1) to return Record2. Similarly, I want to be able to call Model.next or Model.next(1) to return Record4. As another example I want to be able to call Model.previous(2) to return Record3. I think you get the idea.
How can I accomplish this?
To implement something like 'Model.previous', the class itself would have to have a 'current' state. That would make sense if the 'current' record (perhaps in a publishing scheduling system?) was Record3 in your example, but your example doesn't suggest this.
If you want to take an instance of a model and get the next or previous record, the following is a simple example:
class Page < ActiveRecord::Base
def previous(offset = 0)
self.class.first(:conditions => ['id < ?', self.id], :limit => 1, :offset => offset, :order => "id DESC")
end
def next(offset = 0)
self.class.first(:conditions => ['id > ?', self.id], :limit => 1, :offset => offset, :order => "id ASC")
end
end
If so you could do something like:
#page = Page.find(4)
#page.previous
Also working would be:
#page.previous(1)
#page.next
#page.next(1)
Obviously, this assumes that the idea of 'next' and 'previous' is by the 'id' field, which probably wouldn't extend very well over the life of an application.
If you did want to use this on the class, you could perhaps extend this into a named scope that takes the 'current' record as an argument. Something like this:
named_scope :previous, lambda { |current, offset| { :conditions => ['id < ?', current], :limit => 1, :offset => offset, :order => "id DESC" }}
Which means you could call:
Page.previous(4,1)
Where '4' is the id of the record you want to start on, and 1 is the number you want to navigate back.
I added this feature into my gem by_star last month. It may have some other features you're interested in, so check it out.
It works by you having an existing record and then calling previous or next on that:
Page.find(:last).previous
I wrote a gem for doing this for arbitrary order conditions, order_query:
class Issue < ActiveRecord::Base
include OrderQuery
order_query :order_display, [
[:priority, %w(high medium low)],
[:valid_votes_count, :desc, sql: '(votes - suspicious_votes)'],
[:updated_at, :desc],
[:id, :desc]
]
def valid_votes_count
votes - suspicious_votes
end
end
Issue.order_display #=> ActiveRecord::Relation<...>
Issue.reverse_order_display #=> ActiveRecord::Relation<...>
# get the order object, scope default: Post.all
p = Issue.find(31).order_list(scope) #=> OrderQuery::RelativeOrder<...>
p.before #=> ActiveRecord::Relation<...>
p.previous #=> Issue<...>
p.position #=> 5
p.next #=> Issue<...>
p.after #=> ActiveRecord::Relation<...>

Ruby on Rails query by datetime range ( last 24, 48, etc... hours )

I'm trying to build a query that will search for recent entries based on column 'last_login_at'. This is a datetime field with time zone (i.e. Time.zone.now)
When I execute
User.find(:all, :conditions => ["last_login_at < ?", 24.hours.ago])
I get nothing.
Alternatively I can define today as Time.zone.today and yesterday as Time.zone.today - 1.day
and run
User.find(:all, :conditions => ["last_login_at between ? and ?", today, yesterday])
and it still returns 0 results. I know there are some entries that fall into this category.
Old question, but here's newer syntax:
User.where(last_login_at: 3.days.ago..DateTime.now)
Ensure that the timezones you have recorded within the database and those your rails app is outputting are equal. This can sometimes cause an issue. Otherwise try this named scope:
class User < ActiveRecord::Base
named_scope :last_loggedin_before, lambda { |time_ago| { :conditions => ['last_login_at < ?', time_ago] } }
named_scope :last_loggedin_within, lambda { |time_ago| { :conditions => ['last_login_at > ?', time_ago] } }
end
allowing you to do:
User.last_loggedin_before 24.hours.ago
or
User.last_loggedin_within 24.hours.ago

Resources