【问题标题】:Model column that depends on other columns依赖于其他列的模型列
【发布时间】:2023-03-23 00:30:01
【问题描述】:

我有一个游戏化应用程序,它有四种积分,所有这些积分的总和就是用户的总积分,我希望能够在该列上做sumscopes,所以我想我应该把它作为数据库中的一列。

scope :points_rank, -> { order(points: :desc) }

我使用before_save 来添加所有四种point 类型并将其存储在points 中,但现在我使用的gem 对这些类型的点执行increment,所以当它更新这些点时值,before_save 不会被调用,因此不会按预期更新points 值。

什么是正确的 ActiveRecord 回调,而不是 before_save,或者我可以做些什么来保持列更新。

【问题讨论】:

  • 你能分享一下宝石的名字吗?我认为您应该查找 gem 文档以获取回调。
  • 当然,它的counter_culture
  • counter_culture will only update its counters in the after_commit callback。所以我认为你应该尝试after_commit
  • @AmitPatel,它也不起作用,我不明白

标签: ruby-on-rails ruby-on-rails-4


【解决方案1】:

尝试改用after_touch 回调。

after_touch 回调在对象被触摸时触发。

所以,每当点类型发生变化时,它都应该更新points

【讨论】:

  • 我试过了,但没有用,还有其他想法吗?谢谢
【解决方案2】:

首先,counter_culture 似乎是增强rails 的counter_cache 功能的一种方式...

用于缓存关联上所属对象的数量。例如,Post 类中的 comments_count 列包含许多 Comment 实例,将缓存每个帖子的现有 cmets 数。

从你的问题来看,它可能不是正是你想要的。

好的,我明白了。您在 User 模型中使用 points 来创建可用于更广泛的应用程序功能的“缓存”列。好的,这很酷...

--

然后,您的设置将看起来像 (您手动设置了 counter_cache 列,现在 gem 处理它):

#app/models/user.rb
class User < ActiveRecord::Base
   counter_cache :points
end

#app/models/point.rb
class Point < ActiveRecord::Base
   belongs_to :user, counter_cache: true
end

那么问题是,当您更新 points 模型时,您需要能够更新 users 模型中的“缓存”列,现在无需任何回调.


什么是正确的 ActiveRecord 回调而不是 before_save

我假设您在 User 模型上调用 before_save(IE 添加相关数据并放置 points 列?

如果是这样,您应该尝试在 Point 模型上使用回调,可能是这样的:

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :points
end

#app/models/point.rb
class Point < ActiveRecord::Base
   belongs_to :user, inverse_of: :points
   after_commit :update_user

   private

   def update_user
      if user?
          user.update(points: x + y + z)
      end
   end
end

--

观察员

如果您有真正的问题,可以查看ActiveRecord observers

这是我写的一个答案:Ruby On Rails Updating Heroku Dynamic Routes

这是否会在没有任何回调的情况下触发是另一回事,但我可以说的是,它可以为您提供您可能无法访问的功能:

#config/application.rb (can be placed into dev or prod files if required)
config.active_record.observers = :point_observer

#app/models/point_observer.rb
class PointObserver < ActiveRecord::Observer
  def before_save(point)
    #logic here
  end
end

测试它的一个好方法是使用不同的方法(您必须使用rails-observers gem)。即:

 #app/models/point_observer.rb
class PointObserver < ActiveRecord::Observer
  def initialize(point)
     #if this fires, happy days
  end
end

【讨论】:

    猜你喜欢
    • 2013-09-18
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多