0

我不确定这是因为我使用的是 Rails 4,但我很困惑。

I have the following models set:

class Post < ActiveRecord::Base
  has_many :stars, :as => :starable, :dependent => :destroy 
  belongs_to :user
end

class Star < ActiveRecord::Base
  before_create :add_to_total_stars

  belongs_to :starable, :polymorphic => true

  protected

  def add_to_total_stars
    if [Post].include?(starable.class)
      self.starable.update_column(:total_stars, starable.total_stars + self.number)
    end
  end
end

class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
  has_many :votes, dependent: :destroy
end

所以我在 Rails 控制台中创建了一个星号和一个帖子:

star = post.stars.build number: 2
post = Post.create title: "test", content: "test", user_id: 1

然后使用以下内容修改中的average_starspost

star.starable.update(:average_stars, 4)

到目前为止一切正常:

star.starable
 => #<Post id: 9, title: "test", content: "test", created_at: "2013-07-25 16:05:52", updated_at: "2013-07-25 16:05:52", user_id: 1, average_stars: 4, total_stars: 0.0> 

但后来我想检查一下post,我看到了这个:

 post
 => #<Post id: 9, title: "test", content: "test", created_at: "2013-07-25 16:05:52", updated_at: "2013-07-25 16:05:52", user_id: 1, average_stars: 0, total_stars: 0.0> 

average_stars根本没有更新。

为什么 update_column 更新了 star.starable 而不是帖子?

4

1 回答 1

2

这没有错。你starpost对象现在只是在内存中。您更改了 的数据库数据post,但post内存中的对象不会自动重新连接到数据库以更新其内部数据。您必须post.reload手动执行此操作。

根据您的代码的上下文,这可能非常好。

此外,除非您真的,真的,真的想提高性能,average_stars否则不应该是属性/列,而是可以在需要时动态计算的派生属性。

编辑关于制作派生属性,我的意思是你会为它制作一个方法。目前它是您数据库中的一列,因此您可以执行以下操作:

Post.first.average_stars # => 4

相反,average_stars在你的Post模型中创建一个命名的方法:

class Post < ActiveRecord::Base
  # ...
  def average_stars
     # calculate
     return the_result
  end
end

然后你可以像以前一样调用这个方法,但不是从数据库中获取它,而是计算它。您可以记住它,以便在对象的生命周期内不必重新计算它(除非您强制它),但要小心。

于 2013-07-25T16:30:54.870 回答