Last active
August 19, 2016 08:46
-
-
Save solnic/9b9deedd7891e2c7ac83 to your computer and use it in GitHub Desktop.
Virtus pg array type for Sequel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Virtus | |
class PGArray < Attribute | |
primitive Sequel::Postgres::PGArray | |
def primitive | |
options[:primitive] | |
end | |
def coerce(value) | |
Sequel.pg_array(value) | |
rescue | |
value | |
end | |
def value_coerced?(value) | |
value.instance_of?(Sequel::Postgres::PGArray) | |
end | |
end | |
end | |
class Params | |
include Virtus.model(strict: true) | |
attribute :arr, Virtus::PGArray | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
irb(main):007:0> Virtus::Attribute.build(Virtus::PGArray, strict: true).coerce([1,2,3]) | |
=> [1, 2, 3] | |
irb(main):008:0> Virtus::Attribute.build(Virtus::PGArray, strict: true).coerce('') | |
Virtus::CoercionError: Failed to coerce "" into Sequel::Postgres::PGArray |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
tl;dr: You may not need to call
primitive
method within the custom attribute class body, unless you want to make Virtus use the custom attribute#coerce
method to define all attributes of the given primitive.I just found out that unless you want to write a generic coercer for any value of class
Foo
, you better omit theprimitive Foo
part.For example, I wrote a custom coercer for BigDecimal, let's call it
BigDecimalWithOneDecimalPoint
. It tried to coerce the given value to a BigDecimal and then round it to one decimal point.However, because I used
primitive BigDecimal
within theBigDecimalWithOneDecimalPoint
definition, Virtus was using it for all BigDecimal values. Even if I specified that BigDecimal is the type of an attribute:…Virtus would still use
BigDecimalWithOneDecimalPoint
for the coercion.Removing the
primitive
call seems to solve the problem. However, in order to make the strict mode error message correct, you can no longer useoptions[:primitive]
in theprimitive
method. For now, I just made mine method return the desired primitive.I made a reproduction of the issue. However, I'm not sure if I should submit it as a separate Virtus issue, because I think calling
primitive
or definingvalue_coerced?
is using the private API of Virtus. And yeah, I remember you're not working on Virtus. 😉So I post it here to make people aware of the caveats of calling
primitive
.