Blogaomu

WEBアプリケーション開発とその周辺のメモをゆるふわに書いていきます。

update_attribute について(ActiveRecord, Mongoid比較)

ActiveRecord, Mongoidに定義されているupdate_attributeメソッドはバリデーション無しに値を保存しているようです。これを使ってハマったのでメモしておきます。

調査対象

ActiveRecord

ActiveRecordlib/active_record/persistence.rbの該当部分を見てみましょう。

def update_attribute(name, value)
  name = name.to_s
  verify_readonly_attribute(name)
  send("#{name}=", value)
  save(validate: false)
end

処理の最後でsaveメソッドを呼んでいますが、validate: falseになっていますね。

Mongoid

Mongoidのlib/mongoid/persistence.rbの該当部分を見てみましょう。

def update_attribute(name, value)
  normalized = name.to_s
  unless attribute_writable?(normalized)
    raise Errors::ReadonlyAttribute.new(normalized, value)
  end
  write_attribute(database_field_name(normalized), value)
  save(validate: false)
end

こちらも処理の最後でsaveメソッドを呼んでいますが、ActiveRecordと同様にvalidate: falseになっています。(書き込み可能なattributeかどうか判断する処理が両者で異なっているのが興味深いです。今回は深追いしません。)

update_attributes

update_attributesというメソッドを使うとバリデーションを行ってくれますので、普段はこちらを使うのが安全なのかなと思います。

ActiveRecord

def update(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    assign_attributes(attributes)
    save
  end
end

alias update_attributes update

Mongoid

def update_attributes(attributes = {}, options = {})
  assign_attributes(attributes, options); save
end