This project is archived and is in readonly mode.
ActiveModel transformations
-
thoefer
Hey Mike,
I like your idea basically as this is really default functionality! The first thing that comes to my mind was that these transformers should easily be chainable e.g. like rack-middleware. Output of the first transformer could be treated as input to the next transformer. Furthermore I think it´s important to implement the API in a way that custom transformers can easily be added.
What do you think about this:
validates :name, :presence => true, :transformer => [:remove_whitespace, :remove_invalid_chars]
This way the entire chain of transformers is grouped with the validator and easily verifyable.
-
thoefer
And I think it´s important to really distinguish between what´s is implemented as a transformer (and therefore before the validation stage) and what should be a validator.
-
Josep M. Bach
Hi Mike,
I gave it a shot and tried to implement a first basic draft.
https://gist.github.com/846276
I've got it green on ActiveModel master w/ Ruby 1.9.2. There's some stuff pending (inheriting transformations for example).
Somehow I like better the idea of having validations and transformations as two separate sets of callbacks, since they are inherently different concepts. I've mirrored the structure of ActiveModel::Validations, creating a new type of :transform callbacks and all.
The only thing I don't like with this approach is that transformers are not chainasble, and, as @thoefer says, intuitively it would be a nice feature to have.
-
Trevor Turk
Why not just override the setter method?
-
thoefer
You convinced me Josep. I think it´s better to separate validations and transformations. I think the possibility to chain transformers is almost a must-have. Therefore I tried to implement the basic library in this way, as you can see in https://gist.github.com/847786 (please scroll down for the actual AR-model and transformer usage).
It basically looks like this:
class Asset < ActiveRecord::Base include ActiveModel::Transformers # Usage examples for chainable transformer API. UseCases: # - builtin transformer without customized options # - builtin transformer with customized options # - custom transformer (as a lambda) # API for builtin transformers relying on default-options transform :age, :digit, :strip # API for builtin transformer with customized options and a custom transformer transform :name do with :strip, :l => false with lambda {|value| "custom transformer: ...#{value}..."} end end@Trevor: You´re absolutely right with your proposal. Nontheless it would be helpful to have a couple of basic transformers available for filtering.
Comments?
-
thoefer
forgot to mention, sorry: output of one transformer is treated as input value for the next one.
-
Mike Perham
After weekend consideration, I'm now wondering if this shouldn't just be a before_validation and after_validation block for each model. I'm not convinced having separate transform blocks is any cleaner or more useful.
-
thoefer
You´re right, this could be implemented with validation hook also. Nonetheless I think it would be helpful to have some builtin highlevel-transformer available rather than having to deal with low-level-filter e.g. regular expressions.
-
Oriol Gual
@thoefer you may want to look at mdeering's attribute normalizer