読者です 読者をやめる 読者になる 読者になる

【探検】Railsカラム更新のメソッド1

初めに

皆さん、初めまして。そして、明けましておめでとうございます。株式会社MUGENUP 開発部の奥田です。 今回、初めて技術ブログを書くことになりました。よろしくお願い致します。

何回かに分けてRailsのカラム更新メソッドについて書いていき、今回はupdate_attributeupdate_attributesについて記述します。2つのメソッドは私の環境だとactiverecord-3.2.16/lib/active_record/persistence.rbにありました。以下の表は簡単なまとめです。

メソッド名 validation callback 更新カラム数
update_attribute なし あり 1つだけ
update_attributes あり あり 複数

それではそれぞれのメソッドのソースコードを探検してみましょう〜!!

ActiveRecord::Persistence#update_attribute

  # Updates a single attribute and saves the record.
  # This is especially useful for boolean flags on existing records. Also note that
  #
  # * Validation is skipped.
  # * Callbacks are invoked.
  # * updated_at/updated_on column is updated if that column is available.
  # * Updates all the attributes that are dirty in this object.
  #
  def update_attribute(name, value)
    name = name.to_s
    raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
    send("#{name}=", value)
    save(:validate => false)
  end

save(:validate => false)となっているので、validationなしということがわかります。Callbackを起こすは英語でinvokeと表現するのですね〜。updated_atまたはupdated_onは更新するとわざわざ記述しているので、更新しないメソッドもあるのかもしれません。驚いたのはsend("#{name}=", value)の部分で、sendメソッドはカラム名=をメソッドと認識することです。sendメソッドを深堀りするのも面白そうだと思いました。

ActiveRecord::Persistence#update_attributes

  # Updates the attributes of the model from the passed-in hash and saves the
  # record, all wrapped in a transaction. If the object is invalid, the saving
  # will fail and false will be returned.
  #
  # When updating model attributes, mass-assignment security protection is respected.
  # If no +:as+ option is supplied then the +:default+ role will be used.
  # If you want to bypass the protection given by +attr_protected+ and
  # +attr_accessible+ then you can do so using the +:without_protection+ option.
  #
  def update_attributes(attributes, options = {})
    # 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
      self.assign_attributes(attributes, options)
      save
    end
  end

update_attributesにはoptionsがあるんですね〜。:without_protectionoptionsに入れることでmass-assignmentのprotectionチェックなしにできることを初めて知りました。assign_attributesの中も見たい気持ちはありますが、今後のネタとして取っておきます(笑)。コメントアウトで強調したいところを+で囲っていますが、私の知らない記法でした。Markdown記法ではないようなので、要調査です。

番外編 ActiveRecord::Persistence#update_attributes!

#update_attributessaveを呼んでいるのでカラム更新の失敗時に戻り値としてfalseを返します。そして、#update_attribute!をつけた#update_attributes!の場合はカラム更新の失敗時に例外を返しますが、その中身はどうなっているのでしょう?saveが呼ばれて、!がついてるということは・・・?

  # Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
  # of +save+, so an exception is raised if the record is invalid.
  def update_attributes!(attributes, options = {})
    # 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
      self.assign_attributes(attributes, options)
      save!
    end
  end

予想通りですが、save!が呼ばれていました〜。

最後に

簡単にではありましたが、Railsのカラム更新メソッドについて見てきました。この記事を読んで初めて知ったことがあれば幸いです。他にもカラム更新のメソッドはあるので、私の次回の記事でもカラム更新のメソッドを探検したいと思います。

宣伝

MUGENUP では、Rails を使いたいエンジニアを募集中です。 無限流開発、ご一緒しませんか?

大きな裁量で自社サービス開発!Rubyエンジニアをウォンテッド! - 株式会社MUGENUPの求人 - Wantedly

f:id:mgnup:20131118023234p:plain