依赖于其他列的模型列

时间:2015-10-13 05:23:18

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

我有一个游戏化应用程序有四种类型的点,所有这些类型的总和是用户的总点数,我希望能够sumscope上该列,所以我认为我应该把它作为数据库中的一列。

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

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

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

2 个答案:

答案 0 :(得分:1)

请尝试使用after_touch回调。

无论何时触摸对象,都会触发

after_touch回调。

因此,每当点类型发生变化时,都应更新points

答案 1 :(得分:0)

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

  

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

根据你的问题,可能可能不是你想要的。

好的,我明白了。您在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 模型时,你需要能够更新用户模型中的“缓存”列,现在没有任何回调

  

使用正确的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

-

<强> Oberservers

如果您遇到实际问题,可以查看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)。 IE:

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