1

User モデルのフィールドのリストがあります ( Userbelongs_toLocationと 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

このメソッドをリファクタリングする方法についてアドバイスをいただけますか? ありがとうございました!

4

1 に答える 1

0

これは、Rails が既にカバーしていることを行うための大量のコードです。

データベース内の現在の値と比較して属性が変更されたかどうかを確認するchanged?メソッドを既に使用しているようです。

ただし、 を使用するupdate_attributesと、変更が即座に保存されるため、変更を追跡するのが難しくなります。before_saveモデルが更新される直前に、何かが変更されたかどうかを追跡できるコールバックをモデルで使用できます。

例えば:

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

または、 ActiveRecord 自体にパッチを適用して、呼び出した後に変更された属性を返すこともでき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])
于 2012-06-21T10:47:08.683 に答える