将ActiveRecord_Relation的ActiveRecord类方法作为接收方

时间:2015-09-13 07:44:16

标签: ruby-on-rails ruby activerecord activerecord-relation

我想为一个继承class method的类创建ActiveRecord:Base。 该方法需要做的是根据选项添加where子句,并且效果很好。

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

此代码在调用时可以正常工作,例如:

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.

然而,问题在于,如果我想在没有过滤参数的情况下调用list_by_params,那么就会失去以前的关系。例如:

articles = Article.joins(:authors).list_by_params({})
#=> articles is just a `Article` (not an ActiveRecord_Relation) class itself without joining :authors.

我有没有机会犯错?

提前致谢。

2 个答案:

答案 0 :(得分:1)

您要找的是scope

我会做这样的事情

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

现在您可以重用查询的组件。一切都有名称,更容易阅读代码。

答案 1 :(得分:0)

对于自我解释,我使用where(nil)解决了这些问题。

实际上,Model.scoped返回了匿名作用域,但自Rails版本4以来,该方法已被弃用。现在,where(nil)可以替换该功能。

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