Rails after_initialize仅限于"new"

Tyl*_*itt 51 model ruby-on-rails nested-attributes

我有以下2个型号

class Sport < ActiveRecord::Base
  has_many :charts, order: "sortWeight ASC"
  has_one :product, :as => :productable
  accepts_nested_attributes_for :product, :allow_destroy => true
end

class Product < ActiveRecord::Base
  belongs_to :category
  belongs_to :productable, :polymorphic => true
end
Run Code Online (Sandbox Code Playgroud)

如果没有产品,运动就不可能存在,所以sports_controller.rb我的拥有:

def new
  @sport = Sport.new
  @sport.product = Product.new
...
end
Run Code Online (Sandbox Code Playgroud)

我试图将产品的创建转移到运动模型,使用after_initialize:

after_initialize :create_product

def create_product
 self.product = Product.new
end
Run Code Online (Sandbox Code Playgroud)

我很快就知道after_initialize只要模型被实例化(即来自一个find调用)就会被调用.所以这不是我想要的行为.

我应该如何建模所有人sport都有的要求product

谢谢

bos*_*nou 62

如您所述,将逻辑放在控制器中可能是最佳答案,但您可以after_initialize通过执行以下操作来完成工作:

after_initialize :add_product

def add_product
  self.product ||= Product.new
end
Run Code Online (Sandbox Code Playgroud)

这样,它只会在没有产品的情况下设置产品.它可能不值得开销和/或不如在控制器中具有逻辑那么清晰.

编辑:根据Ryan的回答,在性能方面,以下可能会更好:

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end
Run Code Online (Sandbox Code Playgroud)


Pau*_*eon 40

肯定after_initialize :add_product, if: :new_record?是这里最干净的方式.

将条件保留在add_product函数之外

  • after_initialize:add_product,on::create`工作吗? (3认同)

Rya*_*yan 28

如果你这样做self.product ||= Product.new,每次你都会搜索产品,find因为它需要检查它是否为零.因此,它不会做任何急切的加载.为了仅在创建新记录时执行此操作,您可以在设置产品之前检查它是否是新记录.

after_initialize :add_product

def add_product
  self.product ||= Product.new if self.new_record?
end
Run Code Online (Sandbox Code Playgroud)

我做了一些基本的基准测试,检查if self.new_record?似乎没有以任何明显的方式影响性能.

  • 通过编写`after_initialize:add_product,:if =>:new_record?`,也可以将`new_record?`检出`add_product`.在某些情况下,组织会更好. (16认同)