Reputation: 1423
I want to create a class method
for a class inherits ActiveRecord:Base
.
What the method need to do is add where clauses based on the options and it works well.
class Article < ActiveRecord::Base
def self.list_by_params(params={})
articles = self
articles = articles.where(author_id: params[:author_id]) unless params[:author_id].blank?
articles = articles.where(category_id: params[:category_id]) unless params[:category_id].blank?
articles = articles.where("created_at > ?", params[:created_at].to_date) unless params[:created_at].blank?
articles
end
end
This code works fine in case of the call such as:
articles = Article.list_by_params({author_id: 700})
#=> Works fine as I expected.
articles = Article.joins(:authors).list_by_params({author_id: 700})
#=> Works fine as I expected.
However, the problem is that, if I want to call the list_by_params
without filtering params, then it lose its former relations. For example:
articles = Article.joins(:authors).list_by_params({})
#=> articles is just a `Article` (not an ActiveRecord_Relation) class itself without joining :authors.
Is there any chance that I made a mistake?
Thanks in advance.
Upvotes: 0
Views: 232
Reputation: 1423
For the self explanation, I've solved the problems by using where(nil)
.
Actually, Model.scoped
returned anonymous scope but the method has been deprecated since Rails version 4. Now, where(nil)
can replace the functionality.
class Article < ActiveRecord::Base
def self.list_by_params(params={})
articles = where(nil) # <-- HERE IS THE PART THAT I CHANGED.
articles = articles.where(author_id: params[:author_id]) unless params[:author_id].blank?
articles = articles.where(category_id: params[:category_id]) unless params[:category_id].blank?
articles = articles.where("created_at > ?", params[:created_at].to_date) unless params[:created_at].blank?
articles
end
end
Upvotes: 0
Reputation: 3032
What you are looking for is a scope.
I would do something like this
scope :for_author, lambda { |author| where(author_id: author) unless author.blank? }
scope :in_category, lambda { |category| where(category_id: category) unless category.blank? }
scope :created_after, lambda { |date| where('created_at > ?', date.to_date) unless date.blank? }
scope :list_by_params, lambda do |params|
for_author(params[:author_id])
.in_category(params[:category_id])
.created_after(params[:created_at])
end
Now you can reuse the components of your query. Everything has a names and it gets easier to read the code.
Upvotes: 1