update_column更新我的instance.xxxable但不更新实例本身?

时间:2013-07-25 16:20:36

标签: ruby-on-rails

我不确定这是因为我使用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_stars中的post列:

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而不是帖子?

1 个答案:

答案 0 :(得分: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

然后你可以像以前一样调用这个方法,但不是从数据库中抓取它,而是计算它。你可以memoize这样,对于你的物体的生命时间它不必重新计算它(除非你强迫它),但要小心。