pot*_*hin 9 ruby ruby-on-rails ruby-on-rails-4 virtus
假设我们有一个Virtus模型 User
class User
include Virtus.model
attribute :name, String, default: 'John', lazy: true
end
Run Code Online (Sandbox Code Playgroud)
然后我们创建一个这个模型的实例并从中扩展Virtus.model以动态添加另一个属性:
user = User.new
user.extend(Virtus.model)
user.attribute(:active, Virtus::Attribute::Boolean, default: true, lazy: true)
Run Code Online (Sandbox Code Playgroud)
当前输出:
user.active? # => true
user.name # => 'John'
Run Code Online (Sandbox Code Playgroud)
但是当我尝试attributes通过as_json(或to_json)将对象转换为JSON 或Hash通过to_h我只获得扩展后属性时active:
user.to_h # => { active: true }
Run Code Online (Sandbox Code Playgroud)
是什么导致了这个问题,如何在不丢失数据的情况下转换对象?
我发现了一个github问题,但似乎它毕竟没有修复(推荐的方法也没有稳定运行).
在Adrian的发现的基础上,这是一种修改Virtus以允许你想要的东西的方法.所有规格都通过了此修改.
从本质上讲,Virtus已经有了父母的概念AttributeSet,但只有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}
Run Code Online (Sandbox Code Playgroud)
也许值得为Virtus做一个公关,你怎么看?
| 归档时间: |
|
| 查看次数: |
540 次 |
| 最近记录: |