Rails after_initialize只在“新”

我有以下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 

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

 def new @sport = Sport.new @sport.product = Product.new ... end 

我尝试使用after_initialize将产品的创build移动到运动模型:

 after_initialize :create_product def create_product self.product = Product.new end 

我很快就知道,每当一个模型被实例化时(即从一个find调用), after_initialize调用after_initialize 。 所以那不是我正在寻找的行为。

我应该如何模拟所有sport都有product的要求?

谢谢

把逻辑放在控制器中可能是你所说的最好的答案,但你可以通过执行以下after_initialize来获得after_initialize的工作:

 after_initialize :add_product def add_product self.product ||= Product.new end 

这样,只有在没有产品存在的情况下才设置产品。 这可能不值得花费和/或不如控制器中的逻辑清楚。

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

 after_initialize :add_product def add_product self.product ||= Product.new if self.new_record? end 

如果你做self.product ||= Product.new它会每次search一个产品,因为它需要检查是否为零。 因此它不会做任何急切的加载。 为了做到这一点,只有在创build新logging时,您可以在设置产品之前简单地检查它是否是新logging。

 after_initialize :add_product def add_product self.product ||= Product.new if self.new_record? end 

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

当然, after_initialize :add_product, if: :new_record? 这里是最干净的方式。

保持add_product函数的条件

而不是使用after_initialize ,那么after_create呢?

 after_create :create_product def create_product self.product = Product.new save end 

这看起来像会解决你的问题?

看起来你很亲密 你应该能够完全消除after_initialize调用,但首先我相信如果你的运动模型与你所指出的产品有“has_one”的关系,那么你的产品模型也应该“belongs_to”运动。 将其添加到您的产品型号

 belongs_to: :sport 

下一步,你现在应该能够像这样实例化一个运动模型

 @sport = @product.sport.create( ... ) 

这是基于Ruby on Rails指南中关联基础知识的信息,如果我不完全正确,您可以通读这些信息

你应该重写初始化方法

 class Sport < ActiveRecord::Base # ... def initialize(attributes = {}) super self.build_product self.attributes = attributes end # ... end 

从数据库加载logging时,永远不会调用Initialize方法。 请注意,在上面的代码中,属性是在产品生成后分配的。 在这种设置中,属性分配会影响创build的产品实例。