什么时候在 Rails 回调链中分配 Postgres 中的默认值?
Posted
技术标签:
【中文标题】什么时候在 Rails 回调链中分配 Postgres 中的默认值?【英文标题】:When do default values in Postgres get assigned in Rails callback chain? 【发布时间】:2022-01-12 14:56:24 【问题描述】:PostgreSQL 在 Rails 回调链中的哪个点分配任何数据库(非空约束)默认值?
例如,我有一个Experiment
模型,它有一个before_create
回调来设置experiment_type
。一个experiment
has_many Samples
。如果在创建实验时创建了样本,则认为该实验与样本的sample_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
数据库表有约束:
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
。在此之前没有其他回调,因此在源代码中的其他任何地方都没有分配它。
【问题讨论】:
【参考方案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 列,该列在初始化时设置对象的默认值。
【讨论】:
很高兴知道,谢谢 很高兴能帮上忙 提供的两个来源都非常过时(rails 3.1 和 rails 2.3.8)以上是关于什么时候在 Rails 回调链中分配 Postgres 中的默认值?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Boost.ASIO 中分配已连接的本机套接字类型 (TCP)