【问题标题】:Nested collect attribute changes for ActiveRecordActiveRecord 的嵌套收集属性更改
【发布时间】:2012-06-21 09:58:43
【问题描述】:

我有一个用户模型的字段列表(Userbelongs_to Location 和belongs_to Company):

approval_fields = [:email, :location => [:first_name, :last_name], :company => [:name, :address]]

当我尝试通过此代码更新记录时,我想为用户收集所有更改:

user.update_attributes(params[:user])

我为此写了一段丑陋的代码:

# Collects changed fields and returns hash of changes:
# Example: approval_fields = [:email, :location => [:first_name, :last_name]]
#          res = _collect_approval_changes(approval_fields)
#          res # => {'email' => 'new_value@change.com',
#                    'location_attributes' => {'first_name' => 'NewFirstName', 'last_name' => 'NewLastName'}}
def _collect_approval_changes(approval_fields)
  changes = {}
  approval_fields.each do |f|
    if f.is_a?(Hash)
      key = f.keys.first
      next unless self.public_send(key) # skip this association if associated object is nil
      changes["#{key}_attributes"] ||= {}
      f[key].each do |v|
        if self.public_send(key).public_send("#{v}_changed?")
          changes["#{key}_attributes"][v.to_s] = self.public_send(key).read_attribute(v)
        end
      end
      changes.delete("#{key}_attributes") if changes["#{key}_attributes"].blank?
    else
      changes[f.to_s] = self.read_attribute(f) if self.public_send("#{f}_changed?")
    end
  end
  changes
end

你能建议如何重构这个方法吗?谢谢!

【问题讨论】:

    标签: ruby-on-rails nested-attributes


    【解决方案1】:

    Rails 已经为您提供了很多代码。

    我看到您已经在使用changed? 方法将check if an attribute has changed 与数据库中的当前值进行比较。

    但是,由于您使用update_attributes,因此更改会立即保存,因此跟踪更改变得更加困难。您可以在模型上使用before_save 回调,它可以在更新之前跟踪某些内容是否发生了变化。

    例如:

    before_save :check_changed
    def check_changed
      puts (changed? ? "changed" : "unchanged")
    end
    

    或者你可以patch ActiveRecord itself,在你调用update_attributes之后返回改变的属性:

    module ActiveRecord
      class Base
        def update_attributes_changed(attributes)
          self.attributes = attributes
          changes = self.changes
          return save, changes
        end
      end
    end
    
    status, changes = user.update_attributes_changed(params[:user])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 2017-12-30
      • 1970-01-01
      相关资源
      最近更新 更多