JSON哈希值的布尔属性方法 - Rails 4.2,Postgres JSONB

时间:2016-04-07 18:25:53

标签: ruby-on-rails ruby ruby-on-rails-4 jsonb

我有一个带有Foo类型列的模型jsonb,它存储属性的布尔对:

架构:

...
add_column :foos,  :roles, :jsonb, null: :false, default:
  '{
    "bar"   : true,  
    "baz"   : false,
    "fizz"  : false
  }'
...

型号:

class Foo < ActiveRecord::Base
  store_accessor :roles, :bar, :baz, :fizz 
end

有没有办法在不为每个属性编写方法的情况下以布尔值的形式访问这些属性:

能够做到:

foo = Foo.new 
foo.bar? #<= should return 'true'

不添加:

class Foo < ActiveRecord::Base
...
  def bar?
    bar == true 
  end
...
end

2 个答案:

答案 0 :(得分:1)

我认为最接近您的方法是使用define_method动态定义此方法:

class Foo < ActiveRecord::Base
...
  %w(baz bar fizz).each do |method|
    define_method("#{method}?") do
      send(method) == true
    end
  end
...
end

答案 1 :(得分:1)

ActiveRecord :: Store source code概述了最常见的获取getter值的方法是手动定义方法(你已经知道):

  

所有存储的值都可以通过访问器自动获得   Active Record对象,但有时您想要专门化它   行为。这可以通过覆盖默认访问器来完成(使用   与属性相同的名称)并实际调用super   改变一切。

您使用问号方法的情况稍微简单一些。只要jsonb键基本上是字符串,你就可以重构它们以在最后得到那个问号(并且有一个相应的&#34;质疑&#34; getter):

add_column :foos,  :roles, :jsonb, null: :false,
  default: '{ "bar?" : true, ... }'

class Foo < ActiveRecord::Base
  store_accessor :roles, :bar?

正如@Ilya建议的那样,另一个选择是使用一些元编程来定义这些方法(尽管将store_accessor :roles, method移动到循环内部只是为了将所有与商店相关的定义放在一个地方)。 / p>

最后,但并非最不重要的是修补ActiveRecord :: Store :)只要store_accessor基本上只是一个定义getter和setter方法的快捷方式,你可以传递一些额外的参数并定义基于其值的questioned?方法。

以下是使用单独方法实现目标的实现:

module ActiveRecord
  module Store
    module ClassMethods
      def store_accessor_with_question(store_attribute, *keys)
        store_accessor(store_attribute, keys)
        keys.flatten.each do |key|
          define_method("#{key}?") do
            send(key) == true
          end
        end
      end

将其加载到config/initializers文件夹中,您应该能够:

class Foo < ActiveRecord::Base
  store_accessor_with_question :roles, :bar, :baz
end

foo = Foo.new 
foo.bar  #<= true
foo.bar? #<= true