我应该如何在ApplicationRecord对象上设置初始化实例变量?

时间:2017-07-23 15:52:50

标签: ruby-on-rails activerecord initialization

我的应用创建了一个QuoteRequest对象,在将该对象保存到数据库后,我希望它创建一个Quote.new对象(QuoteRequest has_one Quote )。在一个新的Quote实例中,我想设置一些实例变量,这些变量与Watir爬虫相关的各种方法将使用,然后是Watir爬行的结果。 scrape会#save因此将Quote对象持久保存到db。

我想在创建对象后立即在Quote方法中设置initialize个实例变量,但这会产生一个问题,即它继承自ApplicationRecord这个存在初始化冲突。

使用变量实例化ApplicationRecord对象的正确方法是什么,而不与Rails库初始化代码冲突?

2 个答案:

答案 0 :(得分:2)

如果您只想在初始化时设置一个没有任何额外逻辑的实例变量,那么Vijay的答案是一个很好的答案。但是,您可以拥有更多的灵活性,而不仅仅局限于attr方法。

与所有Ruby一样,如果您正在维护与super方法的正确接口,则可以始终利用superActiveRecord::Base#initialize只接受一个可选参数,hash个属性和值。如果给出一个块,它也会将自身产生一个块。 https://github.com/rails/rails/blob/master/activerecord/lib/active_record/core.rb#L313

因此,如果您想在初始化时设置实例变量而不定义任何公共访问方法,您可以:

class Quote < ApplicationRecord
  def initialize(attributes = nil, &block)
    @my_var = attributes.delete(:my_var) if attributes
    super
  end
end

quote = Quote.new(my_var: 'value')
quote.instance_variable_get(:@my_var) # => "value"

您还可以执行更复杂的操作。假设您有User has_many :postsPost belongs_to :userUser:namePost:title

class User < ApplicationRecord
  def initialize(attributes = nil, &block)
    title = attributes.delete(:first_post_title) if attributes
    super
    posts.build(title: "#{name}'s first post: #{title}") if title
  end
end

user = User.new(first_post_title: 'Hello, world!', name: 'Matz')
user.posts.first # => #<Post:xxxxxxxxxxx title: "Matz's first post: Hello, world!">

希望这表明即使使用ActiveRecord个对象也有多么灵活,有时回调在实现中有点过于复杂,并且当super可以正常工作时使用时会有限制,如果适当使用则更好

答案 1 :(得分:1)

对于您不希望保存在数据库中的Quote属性,请创建attr_reader(或attr_accessor)。假设您的Watir方法需要var1var2个对象,那么您的Quote应该如下所示:

class Quote < ApplicationRecord
  attr_reader :var1, :var2
end

然后在after_create的{​​{1}}回调中,您应该像其他任何属性一样将这些变量作为键值对传递。

QuoteRequest

现在,您可以致电obj1 = Var1.new obj2 = Var2.new quote = Quote.new(var1: obj1, var2: obj2, ....)` quote.var1来访问这些内容。在quote.var2上调用save将保留除quotevar1之外的所有在db中具有相应列的属性。