Ruby on rails Setter方法可以';初始化回调后看不到子内置父级

Ruby on rails Setter方法可以';初始化回调后看不到子内置父级,ruby-on-rails,associations,Ruby On Rails,Associations,一封电子邮件有许多变体(用于ab测试),并且始终有一个设置为主版本 我想确保电子邮件总是有一个基于初始化的主变量 我还想将attr访问器“subject”和“body”委托给主变量 我最初尝试使用 delegate :subject, :body, to: :master 但rails抱怨master为零 因此,我尝试手动滚动我自己的subject=setter方法,通过pry我发现,虽然在after_initialize回调中设置了我的master,但对subject=complaints

一封电子邮件有许多变体(用于ab测试),并且始终有一个设置为主版本

我想确保电子邮件总是有一个基于初始化的主变量

我还想将attr访问器“subject”和“body”委托给主变量

我最初尝试使用

delegate :subject, :body, to: :master
但rails抱怨master为零

因此,我尝试手动滚动我自己的subject=setter方法,通过pry我发现,虽然在after_initialize回调中设置了我的master,但对subject=complaints master的后续调用是nil。我不明白为什么

  class Email < ActiveRecord::Base

    has_one :master, 
            -> { where is_master: true },
            class_name: 'Tinycourse::Variant',
            dependent: :destroy,
            inverse_of: :email


    def subject=(str)
      master.subject = str # Rails says master is nil here
    end

    #
    # Callbacks
    #-----------------------------------------

    after_initialize :ensure_master
    def ensure_master
      return unless new_record? 
      self.master ||= build_master
    end
  end


Email.new(:subject => 'yah') # undefined method `subject=' for nil:NilClass
class电子邮件{师父:真的在哪里},
类名:“Tinycourse::Variant”,
依赖::破坏,
电子邮件的反作用
def subject=(str)
master.subject=str#Rails说这里的master为零
结束
#
#回调
#-----------------------------------------
初始化后:确保\u主控
def确保_主机
除非有新的记录,否则返回?
self.master | |=构建主控
结束
结束
Email.new(:subject=>'yah')#nil:NilClass的未定义方法'subject='

当您的电子邮件实例被初始化时,您的
主机
为零,您需要在设置任何内容之前触发
构建主机

那么:

# app/models/email.rb
class Email < ActiveRecord::Base

  def subject=(str)
    master.subject = str # Rails says master is nil here
  end

  def master
    super || build_master
  end
end
…这是另一个用于持久化记录的变体

更新

甚至更好

# app/models/email.rb
class Email < ActiveRecord::Base

  has_one :master, 
          -> { where is_master: true },
          class_name: 'Tinycourse::Variant',
          dependent: :destroy,
          inverse_of: :email

end

# app/lib/email_builder.rb
class EmailBuilder
  attr_reader :args, :subject

  def self.build(args={})
    new(args).build
  end

  def initialize(args)
    @subject = args.fetch(:subject)
    @args = args
  end

  def build
    email = Email.new args
    email.build_master
    email.master.subject = subject 
    email
  end   
end

email = EmailBuilder.build subject: 'yah'
email.class # => Email
#app/models/email.rb
类电子邮件{师父:真的在哪里},
类名:“Tinycourse::Variant”,
依赖::破坏,
电子邮件的反作用
结束
#app/lib/email_builder.rb
类电子邮件生成器
属性读取器:args,:subject
def self.build(args={})
新建(args)。生成
结束
def初始化(args)
@subject=args.fetch(:subject)
@args=args
结束
def构建
email=email.new args
email.build\u master
email.master.subject=主题
电子邮件
结束
结束
email=EmailBuilder.build主题:“耶”
email.class#=>电子邮件

Email.new正在初始化实例,您在初始化后有一个
所以我认为这就是它不起作用的原因。如果你做了
e=Email.new
那么
e.subject='yah'
,它能工作吗?如果我在new之后设置,它能工作。但是,如果我在after_initialize和setter方法中放置pry,那么首先pry在after_initialize处停止,然后它在setter处停止。所以,如果这是命令,大师是建立的,为什么二传看不到它?我不认为这是命令虽然。我认为它试图在初始化时设置它,这将是在构建主程序之前……这样,您将在模型之外提取业务逻辑,使您的模型更轻,测试更快更容易。
# app/models/email.rb
class Email < ActiveRecord::Base

  has_one :master, 
          -> { where is_master: true },
          class_name: 'Tinycourse::Variant',
          dependent: :destroy,
          inverse_of: :email

end

# app/lib/email_builder.rb
class EmailBuilder
  attr_reader :args, :subject

  def self.build(args={})
    new(args).build
  end

  def initialize(args)
    @subject = args.fetch(:subject)
    @args = args
  end

  def build
    email = Email.new args
    email.build_master
    email.master.subject = subject 
    email
  end   
end

email = EmailBuilder.build subject: 'yah'
email.class # => Email