Postgres 中的默认值何时分配到 Rails 回调链中?

When do default values in Postgres get assigned in Rails callback chain?

PostgreSQL 在 Rails 回调链中的哪个点分配任何数据库(非空约束)默认值?

例如,我有一个 Experiment 模型,它有一个 before_create 回调来设置 experiment_type。一个experimenthas_manySamples。如果在创建实验时创建了样本,则该实验被视为与样本 sample_type 相同的 experiment_type。否则,它会被分配数据库的默认值。

class Experiment < ApplicationRecord
  before_create :setup_exp_type

  def setup_exp_type
    sample_set = self.samples.first  # An Experiment has_many samples
    self.experiment_type ||= sample_set&.sample_type
  end

数据库table有约束:

          Column           |            Type             | Collation | Nullable |                      Default                      | Storage  | Stats target | Description 
---------------------------+-----------------------------+-----------+----------+---------------------------------------------------+----------+--------------+-------------
 id                        | integer                     |           | not null | nextval('experiments_id_seq'::regclass)           | plain    |              | 
...
 experiment_type           | experiment_type             |           | not null | '1'::experiment_type                              | plain    |              | 

控制器简单明了:

  def create
    @experiment = Experiment.new(experiment_params)
    respond_to do |format|
      if @experiment.save
        format.html { redirect_to @experiment, notice: 'Experiment was successfully created.' }
        format.json { render :show, status: :created, location: @experiment }
      else
        format.html { render :new }
        format.json { render json: @experiment.errors, status: :unprocessable_entity }
      end
    end
  end

假设在实验创建之前创建了样本并分配给实验,在 setup_exp_type 回调被调用时,我假设数据库默认值尚未分配,因为记录是仍然只在本地内存中。但是,在测试中,我在调试 setup_exp_type 的第二行时看到 self.experiment_type = 1。在此之前没有其他回调,因此它没有被分配到源代码中的其他任何地方。

当你在一个对象上调用new时设置默认值,你可以在方法的源代码中看到here

# File activerecord/lib/active_record/base.rb, line 1543
      def initialize(attributes = nil, options = {})
        @attributes = attributes_from_column_definition
        @association_cache = {}
        @aggregation_cache = {}
        @attributes_cache = {}
        @new_record = true
        @readonly = false
        @destroyed = false
        @marked_for_destruction = false
        @previously_changed = {}
        @changed_attributes = {}
        @relation = nil

        ensure_proper_type
        set_serialized_attributes

        populate_with_current_scope_attributes

        assign_attributes(attributes, options) if attributes

        yield self if block_given?
        run_callbacks :initialize
      end

第一行调用了attributes_from_column_definition,你可以查看here

def attributes_from_column_definition
        self.class.columns.inject({}) do |attributes, column|
          attributes[column.name] = column.default unless column.name == self.class.primary_key
          attributes
        end
      end

正如您在第二行中看到的那样,它正在调用 default 列,它在初始化对象时设置对象的默认值。