Rails 在 after_initialize 中创建 8 条记录,而它应该创建 2 条记录

Rails creating 8 records in after_initialize when it should create 2

我有一个 after_initialize 方法,它应该在初始化 Conference 时创建 2 个子记录,但它却创建了 8 个(每个 4 个)。它似乎不是多线程错误,但我不确定。

conference.rb

class Conference < ApplicationRecord
  has_many :tracks, dependent: :destroy

  after_initialize do
    initialize_tracks
  end

  private

  def initialize_tracks
    one = Track.new(name: 'Track One')
    two = Track.new(name: 'Track Two')
    tracks << one
    tracks << two
  end
end

conference_controller#create

def create
    @conference = Conference.new(conference_params)

    respond_to do |format|
      if @conference.save
        # lines = input_file.read.split(/\n/)
        # lines.each do |line|
        #   next if line.blank?
        #   title, length = line.split(/\d|lightning/)
        #   length = '5min' if length.nil?
        #   @conference.tracks.first.talks << Talk.new(title: title, length: length.scan(/\d/).first)
        # end
        format.html { redirect_to @conference, notice: 'Conference was successfully created.' }
        format.json { render :show, status: :created, location: @conference }
      else
        format.html { render :new }
        format.json { render json: @conference.errors, status: :unprocessable_entity }
      end
    end
  end

track.rb

# == Schema Information
#
# Table name: tracks
#
#  id            :integer          not null, primary key
#  conference_id :integer
#  created_at    :datetime         not null
#  updated_at    :datetime         not null
#  name          :string
#

class Track < ApplicationRecord
  belongs_to :conference
  has_many :talks, dependent: :destroy
end

an after_find and after_initialize callback is triggered for each object that is found and instantiated by a finder, with after_initialize being triggered after new objects are instantiated as well.

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

由于您两次实例化对象(可能在控制器中的newcreate 操作上)代码被调用了两次。


您可以考虑 在控制器上构建轨道

def new
  @conference = Conference.new(conference_params)
  build_tracks
end

def create
  @conference = Conference.new(conference_params)

  respond_to do |format|
    if @conference.save
      format.html { redirect_to @conference, notice: 'Conference was successfully created.' }
      format.json { render :show, status: :created, location: @conference }
    else
      build_tracks
      format.html { render :new }
      format.json { render json: @conference.errors, status: :unprocessable_entity }
    end
  end
end

private

def build_tracks
  return if @conference.tracks.any?

  track_names = ['Track One', 'Track Two']

  track_names.each do |track_name|
    conference.tracks.build(name: track_name)
  end
end