Tony Beninate
Tony Beninate

Reputation: 1985

Rails ActiveRecord query

My question is twofold... Primarily, I am trying to figure out how to ask > or < when filtering this query. You can see at the end I have .where(:created_at > 2.months.ago) and that is improper syntax, but I'm not sure the correct way to call something similar.

Secondly, this is a bit of a long string and is going to get longer as the are more conditions I have to factor in. Is there a cleaner way of building this, or is a long string of conditions like this pretty standard?

class PhotosController < ApplicationController
  def showcase
    @photos = Photo.order(params[:sort] || 'random()').search(params[:search]).paginate(:per_page => 12, :page => params[:page]).where(:created_at > 2.months.ago)
  end

Thanks.

Upvotes: 0

Views: 1438

Answers (2)

numbers1311407
numbers1311407

Reputation: 34072

Unfortunately you've hit a sore point in the ActiveRecord querying api. There is no standard, out of the box way to do this. You can do date ranges very easily, but < and > have no easy path. However Arel, the underlying SQL engine, can do this very easily. You could write a simple scope to handle it thusly:

scope :created_after, lambda {|date| where arel_table[:created_at].gt(date) }

And you could refactor this easily to take a column, or gt versus lt, etc.

Other people have solved this problem already, however, and you could take advantage of their work. One example is MetaWhere, which adds a bunch of syntactic sugar to your queries. For example, using it you might write:

Article.where(:title.matches => 'Hello%', :created_at.gt => 3.days.ago)

On #2, scopes do tend to get long. You might look into the gem has_scope, which helps to alleviate this by defining scopes on the controller in an analogous way to how they are defined on the model. An example from the site:

# The model
# Note it's using old Rails 2 named_scope, but Rails 3 scope works just as well.
class Graduation < ActiveRecord::Base
  named_scope :featured, :conditions => { :featured => true }
  named_scope :by_degree, proc {|degree| { :conditions => { :degree => degree } } }
end

# The controller
class GraduationsController < ApplicationController
  has_scope :featured, :type => :boolean
  has_scope :by_degree

  def index
    @graduations = apply_scopes(Graduation).all
  end
end

Upvotes: 4

Cydonia7
Cydonia7

Reputation: 3826

  • You can do where(["created_at > ?", 2.months.ago]) for your first question.
  • For your second question there are several solutions :
    • You can use scopes to embed the conditions in them and then combine them.
    • You can break the line in multiple lines.
    • You can keep it like this if you have a large screen and you don't work with any other people.

Upvotes: 2

Related Questions