【问题标题】:Is there a better way to record the value of an attribute every day?有没有更好的方法每天记录一个属性的值?
【发布时间】:2015-11-10 22:00:38
【问题描述】:

我有一个模型Thing,其属性rating 会随着时间而改变。我希望能够查看任何Thing.rating 在给定日期的值。

例如,如果 @thing = Thing.first@thing.rating 在 2015 年 1 月 13 日等于 5,我希望能够在未来的任何日期返回该值。

我的一个想法是创建一个名为ThingPast 的新模型,它将属于Thing,而Thing 将拥有_many_of ThingPastThingPast 将具有属性 thing_idratingdate_created。每天的某个时间,一个 Cron 作业会为每个 Thing 创建一个 ThingPast,并复制 rating 属性。

我认为这在技术上可行,但它似乎不必要地复杂和低效。有谁知道更好、更简单的方法来实现这一点?

【问题讨论】:

  • 我认为您所描述的是最合乎逻辑的方法,我很想听听任何替代建议。我只有一条评论可能是将名称从ThingPast 更改为ThingRating。您正在记录现在和过去的值,并且您正在为 Thing 记录 Ratings - 所以最好有一个明显的名称来准确反映这一点。我认为只要您索引thing_id,您就可以使用这种方法。

标签: ruby-on-rails ruby performance cron


【解决方案1】:
  • 添加一个ratings 表,其中包含ratingthing_idcreated_at 列,以及thing_idcreated_at 上的索引。
  • Thing 中删除rating 字段并替换为

    has_many :ratings, order: 'created_at desc'
    
  • ratings 表中将每个新的或更改的评级保存为新记录,例如带有after_save 回调。

  • Thing添加一个方法比如:

    def rating_at(rating_time)
      ratings.where("created_at <= ?", rating_time).first.try(:rating)
    end
    
  • 并替换缺失的字段:

    def rating
      ratings.first.try(:rating)
    end
    

现在,如果您想要每日评分,您可以遍历日期并为每个日期调用 rating_at

    (1..10).map { |days_ago| thing.rating_at(days_ago.days.ago) }.sort

不需要 cron 作业。

【讨论】:

  • 这是一个更好的解决方案,因为如果你真的很在意它,rating 总是与日期(时间)相关联,而thing 在一段时间内可以有多个ratings。跨度>
【解决方案2】:

你可以使用paper_trail gem https://github.com/airblade/paper_trail;它保留模型的版本。它将您选择的所有模型版本存储在与您的模型具有多态关系的versions 表中。

您可以通过查询版本表获得您想要的每日版本

PaperTrail::Version.where(item: Thing.first, created_at: Date.yesterday)

这将为您提供该日期的模型版本

【讨论】:

  • 你知道使用这个 gem 会比每天创建一组新的对象消耗更多或更少的数据库内存吗?
  • 这个 gem 将创建一个新的数据库表 versions 并在模型发生变化时添加一个新记录。所以我认为这与每天创建新对象一样只是一个更通用的解决方案
猜你喜欢
  • 2021-12-08
  • 1970-01-01
  • 2012-08-20
  • 1970-01-01
  • 2012-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-21
相关资源
最近更新 更多