加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – 用于Rails的QueryObject – 如何在ActiveRecor

发布时间:2020-12-17 02:34:18 所属栏目:百科 来源:网络整理
导读:我如何封装一组操作(其中大部分基本上是.where(…))并将其应用于不同的模型,其方式是某些模型可能无法实现某些操作并应返回空集合. (跳过非必要代码) 我设计的(但不满意): class ActivityFinder def self.find(query,limit = nil) activities = get_activit
我如何封装一组操作(其中大部分基本上是.where(…))并将其应用于不同的模型,其方式是某些模型可能无法实现某些操作并应返回空集合. (跳过非必要代码)

我设计的(但不满意):

class ActivityFinder

  def self.find(query,limit = nil)
    activities = get_activities(query)
    activities = activities.sort_by(&:created_at).reverse // some-kind of merge-sort
    activities = activities.slice(0,limit) if limit.present?
    activities
  end

  private

  def self.get_activities(query)
    activities = []
    activities += query.apply(ModelA)
    activities += query.apply(ModelB)
    activities += query.apply(ModelC)
    activities
  end
end

class ActivityQuery

  def created_before(time)
    @created_before = time
    self
  end

  def created_after(time)
    @created_after = time
    self
  end

  def apply(activity)
    activity = activity.where("#{activity.table_name}.created_at < ?",@created_before) if @created_before.present?
    activity = activity.where("#{activity.table_name}.created_at >= ?",@created_after) if @created_after.present?
    // more operations,not all of them are suported by ModelC
  rescue NoMethodError
    return []
  end
end

用法

query = ActivityQuery.new.created_before(last_time).with_hash(...)
activities = ActivityFinder.find(query)

我不喜欢的:

>救援NoMethodError
>如果不同的模型具有不同的字段名称,则必须将其作为查询中的case语句处理,以这种方式将查询对象与每个模型耦合

所以我正在寻找更好实施的建议

UPDATE

问题是我想传递我从ActiveModel获得的任何对象,例如ActiveRecord :: Relation,所以我不能只用这些方法定义一个模块(并在需要时覆盖它)并将它包含在我正在使用的模型中.问题更多的是指向干净设计的正确方向,而不是实现细节,我会以某种方式弄清楚

解决方法

为避免紧耦合,请将特定于模型的代码放入模型中:

class ModelA < ActiveRecord::Base
  scope :created_before,->(timestamp) { where("created_at < ?",timestamp) }
  scope :created_after,->(timestamp) { where("created_at >= ?",timestamp) }
  scope :with_hash,->(hash) { ... }
end

class ModelB < ActiveRecord::Base
  scope :created_before,->(timestamp) { where("other_column < ?",->(timestamp) { where("other_column >= ?",where('false') # empty,chain-able collection
end

现在您可以编写一个可编程的一致界面:

class ActivityQuery

  def apply(activity)
    activity = activity.scoped
    activity = activity.created_before(@created_before) if @created_before.present?
    activity = activity.created_after(@created_after) if @created_after.present?
    activity = activity.with_hash(@hash) if @hash.present?
    activity
  end

end

无需拯救NoMethodError,也无需更多地摆弄模型的实现细节.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读