ActiveRecord でのデータベース操作(INSERT)

データベース操作がどういう風に実現されてるのか、特に SQL文はどうなってるのかを中心に追いかけてみる。

基本的にモデルの新規レコードの作製は ActiveRecord::Baseクラスを継承したモデルのクラスの create()メソッド(パブリック)を各種 attribute値を引数にして呼ぶ。
new して、saveするとか他の流れもあるけど。

ActiveRecord::Baseクラスの active_record/base.rbファイルをみる。

567行目から

      def create(attributes = nil)
        if attributes.is_a?(Array)
          attributes.collect { |attr| create(attr) }
        else
          object = new(attributes)
          object.save
          object
        end
      end

createメソッド自体が new() して、save してる。saveメソッド(パブリック)は

1971行目から

      def save
        create_or_update
      end

create_or_updateメソッドはプライベート。

2235行目から

    private
      def create_or_update
        raise ReadOnlyRecord if readonly?
        result = new_record? ? create : update
        result != false
      end

この中の createメソッドは下記プライベートメソッド。上のパブリックメソッドとは別、引数の有り無しでこんな呼び分けできたのか。(updateメソッドも同様)

2257行目から

      def create
        if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
          self.id = connection.next_sequence_value(self.class.sequence_name)
        end

        quoted_attributes = attributes_with_quotes

        statement = if quoted_attributes.empty?
          connection.empty_insert_statement(self.class.table_name)
        else
          "INSERT INTO #{self.class.quoted_table_name} " +
          "(#{quoted_column_names.join(', ')}) " +
          "VALUES(#{quoted_attributes.values.join(', ')})"
        end

        self.id = connection.insert(statement, "#{self.class.name} Create",
          self.class.primary_key, self.id, self.class.sequence_name)

        @new_record = false
        id
      end

ここで INSERT文を作ってデータベースコネクションを呼び出している。コネクションの prefetch_primary_key?() とか empty_insert_statement() メソッドも使ってる。

このSQL文を、データベース呼び出しとは独立して取り出すのは無理っぽい。updateとか、SQL文を一度ローカル変数にいれないで直接コネクションのメソッド呼び出しの引数にかいてるので、さらに無理っぽい。