我目前正在寻找使用Rails 5.0.0.beta1.1在ActiveRecord::Type::Value之后使用the enum implementation实现自定义类型。
到目前为止,我已经让它正确地将所有内容正确地投射到数据库。
class BitFieldType < ActiveRecord::Type::Value
def initialize(name, mapping, subtype)
@name = name
@mapping = mapping
@subtype = subtype
end
def cast(value)
[...]
end
def deserialize(value)
[...]
end
def serialize(value)
[...]
end
def assert_valid_value(value)
[...]
end
protected
attr_reader :name, :mapping, :subtype
end
class SomeModel < ActiveRecord::Base
decorate_attribute_type(:my_attribute_name, :bit_field) do |subtype|
BitFieldType.new(:my_attribute_name, [...], subtype)
end
end
我遇到的问题是:我想在where()
次调用中整个数组,而不是每个值。
现在,当我打电话给例如:
SomeModel.where(my_attribute_name: [1, 2, 3])
...它将每个值(1
,2
,3
)传递给我的serialize
方法,然后构建一个类似
[...] where my_attribute_name IN (<serialized 1>, <serialized 2>, <serialized 3>)
我宁愿决定该调用的结果,所以基本上将数组[1, 2, 3]
传递给我的serialize
方法,而不是每个值。然后我可以serialize
将其设为一个值,该值应该与=
进行比较:
[...] where my_attribute_name = <serialized [1, 2, 3]>
这可能吗?
编辑:我或多或少地通过猴子修补ActiveRecord::ActiveRecord::ArrayHandler
存档了我想要的内容diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
index 95dbd6a..33077c1 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
@@ -6,6 +6,9 @@ module ActiveRecord
end
def call(attribute, value)
+ if attribute.relation.send(:type_caster).type_cast_where_array?(attribute.name)
+ value = Array.wrap(attribute.type_cast_for_database(value))
+ end
values = value.map { |x| x.is_a?(Base) ? x.id : x }
nils, values = values.partition(&:nil?)
现在使用受保护的方法:type_caster
和新添加的方法.type_cast_where_array?
。
这个新方法必须添加到ActiveRecord :: TypeCaster :: Map:
diff --git a/activerecord/lib/active_record/type_caster/map.rb b/activerecord/lib/active_record/type_caster/map.rb
index 3a367b3..b710081 100644
--- a/activerecord/lib/active_record/type_caster/map.rb
+++ b/activerecord/lib/active_record/type_caster/map.rb
@@ -11,6 +11,10 @@ module ActiveRecord
type.serialize(value)
end
+ def type_cast_where_array?(attr_name)
+ types.type_for_attribute(attr_name.to_s).type_cast_where_array?
+ end
+
protected
attr_reader :types
要使用默认类型ActiveModel :: Type :: Value进行修补,也必须修补:
diff --git a/activemodel/lib/active_model/type/value.rb b/activemodel/lib/active_model/type/value.rb
index 0d2d687..114f85d 100644
--- a/activemodel/lib/active_model/type/value.rb
+++ b/activemodel/lib/active_model/type/value.rb
@@ -50,6 +50,9 @@ module ActiveModel
value.inspect
end
+ def type_cast_where_array?
+ end
+
# These predicates are not documented, as I need to look further into
# their use, and see if they can be removed entirely.
def binary? # :nodoc:
现在在BitFieldType
我可以覆盖该方法以返回true:
class BitFieldType < ActiveRecord::Type::Value
def type_cast_where_array?
true
end
end
最后但并非最不重要的是,ActiveRecord :: TypeCaster :: Connection也必须使用新方法进行修补,以使所有测试都通过。
diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb
index 7ed8dcc..f5623b4 100644
--- a/activerecord/lib/active_record/type_caster/connection.rb
+++ b/activerecord/lib/active_record/type_caster/connection.rb
@@ -12,6 +12,9 @@ module ActiveRecord
connection.type_cast_from_column(column, value)
end
+ def type_cast_where_array?(_attr_name)
+ end
+
protected
attr_reader :table_name
我知道方法名称可能不是最好的,并且使用受保护的方法也很糟糕,但这似乎是一种类型转换数组的方法,其中调用没有太多代码更改和所有activerecord测试传递。
对此有何评论?
答案 0 :(得分:0)
不,这是不可能的。传递给where
时,数组和散列具有特殊含义。 PG Array,JSON和HStore类型以及serialize
类宏存在完全相同的问题。