Reputation: 129
@people = People.scoped
@people = @people.where(...) if ...
@people = @people.where(...) if ...
@people = @people.where(...) if ...
@people = @people.where(...) if ...
Is any ruby existing solutions to make something like
@people = People.scoped
@people.???? do
where(...) if ...
where(...) if ...
where(...) if ...
end
PS: Thanks for answers. But solutions you provide looks like
def self.conditional_scope
where(...) if ...
where(...) if ...
where(...) if ...
end
I think i'll get only last where even if all "if" is true.
Am i right?
Upvotes: 1
Views: 135
Reputation:
Maybe you're looking for a way to avoid explicitly assigning the new scope after every where
clause? You might be interested in this railscast: http://railscasts.com/episodes/212-refactoring-dynamic-delegator. Ryan Bates uses a delegator to achieve code like this:
def self.search(params)
products = scope_builder
products.where("name like ?", "%" + params[:name] + "%") if params[:name]
products.where("price >= ?", params[:price_gt]) if params[:price_gt]
products.where("price <= ?", params[:price_lt]) if params[:price_lt]
products
end
Upvotes: 0
Reputation: 26979
If I understand what you are asking, you only want to apply each scope if a condition exists... you could use a named scope with a lambda, and then chain them:
scope :one, lambda {|condition| condition ? where(...) : {}}
scope :two, lambda {|condition| condition ? where(...) : {}}
...
@people = Person.one(true).two(false)
Upvotes: 1
Reputation: 83680
Yes. You just need to move it to model:
# Controller
@people = People.find_my_guy
# Model
def self.find_my_guy
where(...) if ...
where(...) if ...
where(...) if ...
end
Obviously, you'll need to pass some environment variable to your model if they are used in your statements:
# Controller
@people = People.find_my_guy(params)
# Model
def self.find_my_guy(params)
where(:id => params[:id]) if params[:id]
where('title LIKE (?)', "%#{params[:search]}%") if parmas[:search]
where(...) if ...
end
As far as you're right about last where
I can suggest only method chaining here (simmilar as @socjopata did(:
# Model
def self.with_name(name)
where(:name => name) if name.present?
end
def self.with_id_gt(id)
where('id >= ?', id) if id.to_i > 3
end
# Controller
Post.with_name(parms[:name]).with_id_gt(params[:id])
Upvotes: 1
Reputation: 115521
def self.conditional_scope
where(...) if ...
where(...) if ...
where(...) if ...
end
Then:
Model.conditional_scope
Upvotes: 1
Reputation: 5095
I think you should get yourself familiar with named_scopes: http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html
They are composable, so you can write something like:
People.tall.having_children.older_than(30)
where "tall", "having_children" and "older_than" are named scopes.
Upvotes: 2