ActiveRecordがテーブルについて知る必要がある場合、 information_schema
と同様のクエリを実行します。 クエリを実行しますが、ARはPostgreSQL固有のシステムテーブル
代わりに:
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
PostgreSQLアダプターソースを検索します 「regclass」の場合、ARがテーブルの構造を理解するために使用する他のクエリがいくつか表示されます。
pg_get_expr コード>
上記のクエリでの呼び出しは、列のデフォルト値の取得元です。
そのクエリの結果は、多かれ少なかれ、 PostgreSQLColumn.new
に直接アクセスします
:
def columns(table_name, name = nil)
# Limit, precision, and scale are all handled by the superclass.
column_definitions(table_name).collect do |column_name, type, default, notnull|
PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
end
end
PostgreSQLColumn
コンストラクター
<を使用しますcode> extract_value_from_default
デフォルトをRuby化する。 スイッチ
extract_value_from_default
で ここで興味深いです:
else
# Anything else is blank, some user type, or some function
# and we can't know the value of that, so return nil.
nil
したがって、デフォルト値がシーケンスにバインドされている場合( id
PostgreSQLの列は)になり、デフォルトは次のような関数呼び出しとしてデータベースから出力されます:
nextval('models_id_seq'::regclass)
それは上記のelse
になります ブランチとcolumn.default.nil?
本当になります。
id
の場合 列これは問題ではありません。ARはデータベースがid
の値を提供することを期待しています。 列なので、デフォルト値は関係ありません。
列のデフォルトがARが理解できないものである場合、これは大きな問題です。 md5(random()::text)
として
。問題は、ARがすべての属性をデフォルト値に初期化することです– Model.columns
Model.new
と言うと、データベースが認識するのではなく、それらが表示されます。 。たとえば、コンソールには次のようなものが表示されます。
> Model.new
=> #<Model id: nil, def_is_function: nil, def_is_zero: 0>
したがって、 def_is_function
実際にはデフォルト値として関数呼び出しを使用しますが、ARはそれを無視し、その列の値としてNULLを挿入しようとします。そのNULLは、デフォルト値が使用されるのを防ぎ、混乱を招く混乱を招きます。ただし、ARが理解できるデフォルト(文字列や数値など)は問題なく機能します。
その結果、ActiveRecordで重要なデフォルトの列値を実際に使用することはできません。重要な値が必要な場合は、RubyでActiveRecordコールバックの1つ( before_create
> 。
IMOがデフォルト値を理解していない場合、ARがデフォルト値をデータベースに任せた方がはるかに良いでしょう。それらをINSERTから除外するか、VALUESでDEFAULTを使用すると、はるかに良い結果が得られます。もちろん、ARは、すべての適切なデフォルトを取得するために、データベースから新しく作成されたオブジェクトをリロードする必要がありますが、ARが理解できないデフォルトがあった場合にのみ、リロードが必要になります。 else
の場合 extract_value_from_default
で nil
の代わりに、特別な「これが何を意味するのかわからない」フラグを使用しました その場合、「最初の保存後にこのオブジェクトをリロードする必要があります」という条件を検出するのは簡単で、必要な場合にのみリロードします。
上記はPostgreSQL固有ですが、プロセスは他のデータベースでも同様である必要があります。ただし、保証はいたしません。