追ってみました。答えは mysql_insert_id() を使っているです。終わり。
コードリーディング
一応コードリーディングした時のメモを残しておきます。諸事情によりRailsのバージョンは 4.1.1
です。
activerecord-4.1.1/lib/active_record/persistence.rb
def save!(*)
create_or_update || raise(RecordNotSaved)
end
def create_or_update
raise ReadOnlyRecord if readonly?
result = new_record? ? create_record : update_record
result != false
end
def create_record(attribute_names = @attributes.keys)
attributes_values = arel_attributes_with_values_for_create(attribute_names)
new_id = self.class.unscoped.insert attributes_values
self.id ||= new_id if self.class.primary_key
@new_record = false
id
end
self.class.unscoped.insert
で新しいIDが返るので実装を探す
activerecord-4.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
value = exec_insert(sql, name, binds, pk, sequence_name)
id_value || last_inserted_id(value)
end
last_inserted_id
で取得している。
ここから mysql2_adapter
の世界。
activerecord-4.1.1/lib/active_record/connection_adapters/mysql2_adapter.rb
def last_inserted_id(result)
@connection.last_id
end
def connect
@connection = Mysql2::Client.new(@config)
configure_connection
end
@connection
にはMysql2::Client
が入るので、ここからはmysql2
の世界
mysql2-0.3.15/ext/mysql2/client.c
/* call-seq:
* client.last_id
*
* Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE
* statement.
*/
static VALUE rb_mysql_client_last_id(VALUE self) {
GET_CLIENT(self);
REQUIRE_CONNECTED(wrapper);
return ULL2NUM(mysql_insert_id(wrapper->client));
}
というわけで mysql_insert_id() を使っているでした。