我有一个带有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
答案 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