ruby-on-rails - 动态扩展 Virtus 实例属性

标签 ruby-on-rails ruby ruby-on-rails-4 virtus

假设我们有一个 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< 将对象转换为 JSON 时 通过 to_h 我只得到后扩展属性 active:

user.to_h # => { active: true }

是什么导致了这个问题,我怎样才能在不丢失数据的情况下转换对象?

附言

我找到了 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 做一个 PR,你怎么看?

关于ruby-on-rails - 动态扩展 Virtus 实例属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44046603/

相关文章:

ruby-on-rails - 使用 Rails 6 实现 Google Adsense

ruby - 在 Ruby 2.3.1 中列出子类

postgresql - 根据时间 block 创建结果数组

ruby-on-rails - 我如何在 Rails 4 中为需要两个以上投票选项的博文创建投票系统?

mysql - 在 activerecord 中可能使用连接将两个 SQL 查询减少为一个

ruby-on-rails - 在应用程序 Controller 中使用 before_filter 并排除

mysql - 来自多个模型的包含、选择、排序、限制(单个查询)

ruby - 在 Ruby 语言中,如何获取字符串中的行数?

ruby - Ruby 中的 "Gemfile"在哪里?

ruby-on-rails - 过滤器链因强制 SSL 呈现或重定向而停止