新手问题 Ruby China 源码中 求解释 follow_user 方法中 push 方法

xiao__liang · 2016年05月13日 · 最后由 xiao__liang 回复于 2016年05月15日 · 1943 次阅读

在看 ruby China 源码时发现 实现用户关注是往 user 的 following_ids 这个字段数组中 添加被关注用户的 ID,但是为什么要用 push 方法,并且用事务方法保护呢?

def follow_user(user)
    return false if user.blank?
    self.transaction do
      self.push(following_ids: user.id)
      user.push(follower_ids: self.id)
    end
    Notification.notify_follow(user.id, self.id)
  end

push 方法如下,调用时传入的是 follower_ids: self.id

def push(hash)      #调用时传入的是follower_ids: self.id键值对,为什么参数那里却是hash, 
    hash.each_key do |key|  
      self.send("#{key}_will_change!") #attribute_will_change方法起到什么作用呢
      old_val = self[key] || []  #self[key],user[key]结果是? 
      old_val << hash[key].to_i
      old_val.uniq!
      update_attributes(key => old_val)
    end
  end

push 方法为什么这么写呢,attribute_will_change 方法起到什么作用呢 我查到的 attribute_will_change 有关的内容是:

是当在一个 model 中和数组(或者其他可变数值)交互的时候。ActiveRecord 现在并没有跟踪"destructive",或者更改发生的地方。这包括数组的 push 和 pop 操作。如果你需要使用"destructive"更新,你必须使用 call<属性>_will_change!

其中 destructive update 是指的哪种情况呢?有什么例子么

其中 stackoverfllow 上有这么一段关于 attribute_will_change 的,但是看的不甚明了,能帮忙解释下么 This is part of activemodel's change tracking system, which active record uses to know what it needs to write to the db (if anything). When you call save on a record, then activerecord creates an update query for all the attributes that it considers changed (and if there are no changed attributes then it does nothing at all).

The accessors that activerecord generates for you handle this for you automatically, but in some cases its useful to tell activerecord that an attribute is dirty and needs changing (for example if you update something in place, circumventing the usual change tracking mechanism). This is exactly what happens here: when you set a key for the stored attribute - rails modifies the hash (as opposed to assigning a new hash), and so a call to _will_change! is needed to keep the change tracking informed that the underlying attribute will need writing to the db the next time save is called.

这段中提到的脏属性是什么意思

还有我在想为甚么

def follow_user(user)
      return false if user.blank?
      self.transaction do
        self.following_ids += [user.id]
        self.save
        user.follower_ids += [self.id]
        user.save
    end
end

这样写比起原来的缺陷在哪呢

@huacnlee 华顺哥请问这里为什么这么写呢

之前回答过一次... 这是个遗留问题, Ruby-China 过去一直使用 MongoDB,前阵子才迁移到 PG,这里应该是兼容过去的设计才这样做的,是在模拟 Mongoid 的多对多关联的实现方式

@jasl 找到了原帖,谢谢了。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册