ARのsaveとかupdate_attributeとか

ActiveRecordのsaveやupdate_attribute(s)がどのような仕組みになっているのかのメモ

環境

  • rails1.2.3

ソースコード

# activerecord/lib/active_record/base.rb
1545       def save
1546         create_or_update
1547       end

# 中略

1584       def update_attribute(name, value)
1585         send(name.to_s + '=', value)
1586         save
1587       end

# 中略

1591       def update_attributes(attributes)
1592         self.attributes = attributes
1593         save
1594       end

# 中略

1787     private
1788       def create_or_update
1789         raise ReadOnlyRecord if readonly?
1790         result = new_record? ? create : update
1791         result != false
1792       end
1793       
1794       # Updates the associated record with values matching those of the instance attributes.
1795       # Returns the number of affected rows.
1796       def update
1797         connection.update(
1798           "UPDATE #{self.class.table_name} " +
1799           "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
1800           "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
1801           "#{self.class.name} Update"
1802         )
1803       end
1804 
1805       # Creates a record with values matching those of the instance attributes
1806       # and returns its id.
1807       def create
1808         if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
1809           self.id = connection.next_sequence_value(self.class.sequence_name)
1810         end
1811       
1812         self.id = connection.insert(
1813           "INSERT INTO #{self.class.table_name} " +
1814           "(#{quoted_column_names.join(', ')}) " +
1815           "VALUES(#{attributes_with_quotes.values.join(', ')})",
1816           "#{self.class.name} Create",
1817           self.class.primary_key, self.id, self.class.sequence_name
1818         )
1819 
1820         @new_record = false
1821         id
1822       end


結局は、saveメソッドもupdate_atteribute(s)も全ては、createメソッドもしくは、updateメソッドを呼び出している
それらのメソッドの内容をもとに、SQLが走る


では、validation周りはどのように制御されているのか?

validationのソースコード

# activerecord/lib/active_record/validations.rb
# module Validations
218     def self.included(base) # :nodoc:
219       base.extend ClassMethods
220       base.class_eval do
221         alias_method_chain :save, :validation
222         alias_method_chain :save!, :validation
223         alias_method_chain :update_attribute, :validation_skipping
224       end
225     end


saveメソッドやupdate_attributeメソッドがoverrideされている。
その内容は?

# activerecord/lib/active_record/validations.rb
# module Validations
733       private

750     def save_with_validation(perform_validation = true)
751       if perform_validation && valid? || !perform_validation
752         save_without_validation
753       else
754         false
755       end
756     end


単にDBに突っ込む前にvalid?かどうかを見ている。
valid? #=> trueであればAR::Base#saveが実行される


さて、perform_validationは何をしているのか?
save(false)として呼び出したときに、validationを通さずに、DBに保存するようにしている。

# activerecord/lib/active_record/validations.rb
# module Validations
733       private

771     def update_attribute_with_validation_skipping(name, value)
772       send(name.to_s + '=', value)
773       save(false)
774     end


update_attributeメソッドの場合、save(false)として呼び出しており、
validationを通らないので、誤った情報がDBに書き加えられることになる可能性があるので、要注意



最後までお読みいただきありがとうございました。