How to override default deserialization of params to model object?
In other words, how to make Rails understand camel case JSON with a snake case database?
Example: I receive params Foo object with a field fooBar and I want my Foo model to understand fooBar is in fact database field foo_bar.
"Foo": {
"fooBar": "hello" /* fooBar is database field foo_bar */
}
class Foo < ActiveRecord::Base
attr_accessible :foo_bar
end
class FoosController < ApplicationController
def new
@foo = Foo.new(params[:foo])
end
Foo.new(params[:foo]) assumes params[:foo] contains foo_bar. Instead params[:foo] contains fooBar (in my case params contains JSON data).
I would like a clean way to handle this case, the same way a model can override as_json:
class Foo < ActiveRecord::Base
attr_accessible :foo_bar, :another_field
def as_json(options = nil)
{
fooBar: foo_bar,
anotherField: another_field
}
end
end
There is a from_json method inside ActiveModel but it is not called when Foo.new(params[:foo]) is run.
I’ve read several times that overriding initialize from a model object is a terrible idea.
I’ve checked active_model_serializers, RABL and JBuilder. None of them allow to customize the JSON format that is received.
For that one must deal with wrap_parameters, see http://edgeapi.rubyonrails.org/classes/ActionController/ParamsWrapper.html
It works, still the code is ugly: I get JSON stuff inside my controller + the serializer/model instead of one place.
Example of use of wrap_parameters:
and then inside my model (Frederick Cheung is right on this part):
For info ASP.NET MVC (with Json.NET) does it using C# decorator attributes which is pretty elegant:
I have created a gist that shows how to implement serialization/deserialization: https://gist.github.com/3858908