我的应用创建了一个QuoteRequest
对象,在将该对象保存到数据库后,我希望它创建一个Quote.new
对象(QuoteRequest
has_one
Quote
)。在一个新的Quote
实例中,我想设置一些实例变量,这些变量与Watir爬虫相关的各种方法将使用,然后是Watir爬行的结果。 scrape会#save因此将Quote对象持久保存到db。
我想在创建对象后立即在Quote
方法中设置initialize
个实例变量,但这会产生一个问题,即它继承自ApplicationRecord
这个存在初始化冲突。
使用变量实例化ApplicationRecord
对象的正确方法是什么,而不与Rails库初始化代码冲突?
答案 0 :(得分:2)
如果您只想在初始化时设置一个没有任何额外逻辑的实例变量,那么Vijay的答案是一个很好的答案。但是,您可以拥有更多的灵活性,而不仅仅局限于attr
方法。
与所有Ruby一样,如果您正在维护与super方法的正确接口,则可以始终利用super
。 ActiveRecord::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 :posts
和Post belongs_to :user
,User
有:name
而Post
有: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方法需要var1
和var2
个对象,那么您的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
将保留除quote
,var1
之外的所有在db中具有相应列的属性。