Rails 3 ActiveRecord conditional includes? - ruby-on-rails

I know this can be done:
Article.where("published_at <= ?", Time.now).includes(:comments)
But what if I'd like to only get comments posted in the past month?
Does the .includes operator allow conditions?

Article.includes(:comments).where("articles.published_at <= ? and comments.created_at >= ?", Time.now, Time.now - 1.month)
EDIT:
Article.joins(:comments).where("articles.published_at <= ? and comments.created_at >= ?", Time.now, Time.now - 1.month)

In Rails4, it should be:
Article.includes(:comments).where("articles.published_at <= ? and comments.created_at >= ?", Time.now, Time.now - 1.month).references(:comments)
Source

Related

ActiveRecord multiple where date range

Is there a more ActiveRecord idiomatic way to find which records have a start_at or end_at within a certain date_range? (Basically, need to find the records that start or end in a given time frame). Here's what I'm currently doing:
Project.where('(start_at >= ? AND start_at <= ?) OR (end_at >= ? AND end_at <= ?)', start_at, end_at, start_at, end_at)
You can pass ranges to where and use or:
time_range = (start_at..end_at)
Project.where(start_at: time_range).or(Project.where(end_at: time_range))
For Rails 4 you could use BETWEEN and hash params:
Project.where(
"(start_at BETWEEN :start_at AND :end_at) OR (end_at BETWEEN :start_at AND :end_at)",
start_at: start_at.beginning_of_day, end_at: end_at.end_of_day)

Substrack in where clause

I'm writting rake task, but cant get my code to work. Is it possible to write like this?
Model.where('(? - begins_at)/3600 > ?', Time.now, 2).all
WHat am i trying to achieve is to return me list of records that are older then 2 hours
Try with that:
Model.where('begins_at < ?', Time.zone.now - 2.hours).all
Try this:
Model.where(['(? - begins_at) > ?', Time.now, 1]).all
As per your comment you can do like this:
Model.where('begins_at < ?', Time.now - 2.hours).all

rails find created_on withing last 5 minutes

I have the following code:
#gameRequests = GameRequest.find(:first, :conditions => ["created_on >= ?", created_on])
I'd like to find the oldest record within the last 5 minutes. How can I subtract the 5 minutes from created_on to do this? I cant seem to find any examples.
Thanks
The code you want is:
#gameRequest = GameRequest.first(:conditions => ["created_on >= ?", DateTime.now - 5.minutes])
BTW, are you sure the field is named created_on and not created_at? Also, .first gets only the first record, not all of them. For that, you need .all
gameRequests = GameRequest.find(:first, :conditions => ["created_on >= ?", created_on - 5.minute])
Try this:
#gameRequests = GameRequest.find(:first, :conditions => ["created_at >= ?", Time.now - 5.minutes], :order => "created_at ASC")

Combine arrays of conditions in Rails

I'm using the Rails3 beta, will_paginate gem, and the geokit gem & plugin.
As the geokit-rails plugin, doesn't seem to support Rails3 scopes (including the :origin symbol is the issue), I need to use the .find syntax.
In lieu of scopes, I need to combine two sets of criteria in array format:
I have a default condition:
conditions = ["invoices.cancelled = ? AND invoices.paid = ?", false, false]
I may need to add one of the following conditions to the default condition, depending on a UI selection:
#aged 0
lambda {["created_at IS NULL OR created_at < ?", Date.today + 30.days]}
#aged 30
lambda {["created_at >= ? AND created_at < ?", Date.today + 30.days, Date.today + 60.days]}
#aged > 90
lamdba {["created_at >= ?", Date.today + 90.days]}
The resulting query resembles:
#invoices = Invoice.find(
:all,
:conditions => conditions,
:origin => ll #current_user's lat/lng pair
).paginate(:per_page => #per_page, :page => params[:page])
Questions:
Is there an easy way to combine these two arrays of conditions (if I've worded that correctly)
While it isn't contributing to the problem, is there a DRYer way to create these aging buckets?
Is there a way to use Rails3 scopes with the geokit-rails plugin that will work?
Thanks for your time.
Try this:
ca = [["invoices.cancelled = ? AND invoices.paid = ?", false, false]]
ca << ["created_at IS NULL OR created_at < ?",
Date.today + 30.days] if aged == 0
ca << ["created_at >= ? AND created_at < ?",
Date.today + 30.days, Date.today + 60.days] if aged == 30
ca << ["created_at >= ?", Date.today + 90.days] if aged > 30
condition = [ca.map{|c| c[0] }.join(" AND "), *ca.map{|c| c[1..-1] }.flatten]
Edit Approach 2
Monkey patch the Array class. Create a file called monkey_patch.rb in config/initializers directory.
class Array
def where(*args)
sql = args[0]
unless (sql.is_a?(String) and sql.present?)
return self
end
self[0] = self[0].present? ? " #{self[0]} AND #{sql} " : sql
self.concat(args[1..-1])
end
end
Now you can do this:
cond = []
cond.where("id = ?", params[id]) if params[id].present?
cond.where("state IN (?)", states) unless states.empty?
User.all(:conditions => cond)
I think a better way is to use Anonymous scopes.
Check it out here:
http://railscasts.com/episodes/112-anonymous-scopes

Use the same parameters many times in a find conditions: hash

I have a model who holds 2 properties: valid_from and valid_to.
I need to select all instances that are currently valid, i.e. valid_from <= today and valid_to >= today.
i have the following find :
Mymodel.find(:all, :conditions => ["valid_from <= ? and valid_to >= ?", Date.today, Date.today])
I already thought about storing Date.today in a variable and calling that variable, but i still need to call it twice.
my_date = Date.today
Mymodel.find(:all, :conditions => ["valid_from <= ? and valid_to >= ?", my_date, my_date])
Is there a way to improve and do only one call to the variable to match all the "?" in the :conditions ?
thanks,
P.
I would use named_scope. In model add:
named_scope :valid,
:conditions =>
["valid_from <= ? and valid_to >= ?", Date.today, Date.today]
And then in your controller you can call:
#mymodels = Mymodel.valid
I think that focusing on reducing two calls to Date.today to only one call is wasting of time. It won't make your application faster or using less memory.
I'm not aware of a way to do what you're asking, but even if you could I don't think it would buy you much. I would create a named scope within your model class.
In this example, you can pass the date to the named scope, or it will default to today's date if no date is specified:
named_scope :by_valid_date, lambda { |*args|
{ :conditions => ["valid_from <= ? and valid_to >= ?",
(args.first || Date.today), (args.first || Date.today)]} }

Resources