假设我们有一个Virtus模型User
class User
include Virtus.model
attribute :name, String, default: 'John', lazy: true
end
然后,我们创建此模型的实例,并从Virtus.model
扩展以动态添加另一个属性:user = User.new
user.extend(Virtus.model)
user.attribute(:active, Virtus::Attribute::Boolean, default: true, lazy: true)
电流输出:user.active? # => true
user.name # => 'John'
但是,当我尝试获取attributes
或通过as_json
(或to_json
)或Hash
通过to_h
将对象转换为JSON时,我仅获得后扩展属性active
:user.to_h # => { active: true }
是什么引起问题,如何在不丢失数据的情况下转换对象?P.S.
我已经找到了github issue,但似乎毕竟并没有解决(推荐的方法也无法稳定运行)。
最佳答案
根据Adrian的发现,这是一种修改Virtus以允许您想要的方法。所有规范均通过此修改。
本质上,Virtus已经具有父AttributeSet
的概念,但是仅当在class中包括Virtus.model
时才如此。
我们也可以将其扩展为考虑实例,甚至允许在同一对象中使用多个extend(Virtus.model)
(尽管听起来不太理想):
require 'virtus'
module Virtus
class AttributeSet
def self.create(descendant)
if descendant.respond_to?(:superclass) && descendant.superclass.respond_to?(:attribute_set)
parent = descendant.superclass.public_send(:attribute_set)
elsif !descendant.is_a?(Module)
if descendant.respond_to?(:attribute_set, true) && descendant.send(:attribute_set)
parent = descendant.send(:attribute_set)
elsif descendant.class.respond_to?(:attribute_set)
parent = descendant.class.attribute_set
end
end
descendant.instance_variable_set('@attribute_set', AttributeSet.new(parent))
end
end
end
class User
include Virtus.model
attribute :name, String, default: 'John', lazy: true
end
user = User.new
user.extend(Virtus.model)
user.attribute(:active, Virtus::Attribute::Boolean, default: true, lazy: true)
p user.to_h # => {:name=>"John", :active=>true}
user.extend(Virtus.model) # useless, but to show it works too
user.attribute(:foo, Virtus::Attribute::Boolean, default: false, lazy: true)
p user.to_h # => {:name=>"John", :active=>true, :foo=>false}
也许值得对Virtus进行公关,您如何看待?
关于ruby-on-rails - 动态扩展Virtus实例属性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44046603/