在没有`attr_accessor`的情况下为rails模型设置非数据库属性

在PHP中,我可以在模型中设置属性(不是数据库中的列)。 例如(PHP代码),

$user = new User; $user.flag = true; 

但是在rails中,当我设置数据库中不存在的任何属性时,它将抛出一个错误的undefined method flag 。 有attr_accessor方法,但如果我需要大约十个临时属性会发生什么?

这是预期的,因为它是ActiveRecord的设计工作方式。 如果需要设置任意属性,则必须使用不同类型的对象。

例如,Ruby提供了一个名为OpenStruct的库,它允许您创建可以分配任意键/值的对象。 您可能希望使用此类库,然后仅在需要保存到数据库时将对象转换为相应的ActiveRecord实例。

不要试图将ActiveRecord建模为刚刚描述的行为,因为它根本不是设计成以这种方式运行的。 这将是您当前的PHP知识中的货物结果错误。

但是如果我需要大约十个临时属性会发生什么?

 #app/models/user.rb class User < ActiveRecord::Base attr_accessor :flag, :other_attribute, :other_attribute2, :etc... end 

attr_accessor在Rails中创建“虚拟”属性 - 它们不存在于数据库中,但存在于模型中。

与db中的属性一样, attr_accessor只是在您的类中创建一组settergetter (实例)方法,您可以在初始化类时调用它们并与之交互:

 #app/models/user.rb class User < ActiveRecord::Base attr_accessor :flag # getter def flag @flag end # setter def flag=(val) @flag = val end end 

正如这些家伙解释的那样, attr_accessor只是一个快速的settergetter

我们可以将我们的模型attr_accessor在记录初始化时设置为Ruby#Hash ,例如使用ActiveRecord#After_initilize方法,这样我们就可以更灵活地临时存储值( 想法归功于这个答案 )。

就像是:

 class User < ActiveRecord::Base attr_accessor :vars after_initialize do |user| self.vars = Hash.new end end 

现在你可以这样做:

 user = User.new #set user.vars['flag'] = true #get user.vars['flag'] #> true 

attr_accessor所做的就是添加使用实例变量的getter和setter方法,例如this

 attr_accessor :flag 

将添加这些方法:

 def flag @flag end def flag=(val) @flag = val end 

如果需要,您可以自己编写这些方法,并让它们做一些更有趣的事情,而不仅仅是将值存储在实例var中,如果需要的话。

如果需要临时属性,可以将它们添加到单例对象中。

 model = Model.new class << model attr_accessor :name end