如何覆盖对模型对象的params的默认反序列化? 换句话说,如何让Rails了解带有蛇案例数据库的驼峰JSON?
示例:我收到带有字段Foo
的params fooBar
对象,我希望我的Foo
模型理解fooBar
实际上是数据库字段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])
假设params[:foo]
包含foo_bar
。相反,params[:foo]
包含fooBar
(在我的情况下params
包含JSON数据)。
我想要一种干净的方式来处理这种情况,就像模型可以覆盖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
有一个from_json
method inside ActiveModel,但在Foo.new(params[:foo])
运行时不会调用它。
我已多次读过从模型对象中覆盖initialize
这是一个糟糕的主意。
答案 0 :(得分:2)
我检查了active_model_serializers,RABL和JBuilder。它们都不允许自定义收到的JSON格式。
为此,必须处理wrap_parameters,请参阅http://edgeapi.rubyonrails.org/classes/ActionController/ParamsWrapper.html 它的工作原理仍然是代码很难看:我在控制器中找到JSON东西+序列化器/模型而不是一个地方。
wrap_parameters的使用示例:
class EventsController < ApplicationController
wrap_parameters :event, include: [:title, :start, :end, :allDay, :description, :location, :color]
def create
respond_with Event.create(params[:event])
end
end
然后在我的模型中(Frederick Cheung就在这一部分):
class Event < ActiveRecord::Base
attr_accessible :title, :start, :end, :allDay, :description, :location, :color
# JSON input allDay is all_day
alias_attribute :allDay, :all_day
# JSON input start is starts_at
# +datetime+:: UNIX time
def start=(datetime)
self.starts_at = Time.at(datetime)
end
# JSON input end is starts_at
# +datetime+:: UNIX time
def end=(datetime)
self.ends_at = Time.at(datetime)
end
# Override the JSON that is returned
def as_json(options = nil)
{
id: id,
title: title,
start: starts_at, # ISO 8601, ex: "2011-10-28T01:22:00Z"
end: ends_at,
allDay: all_day,
description: description, # Not rendered by FullCalendar
location: location,
color: color
}
end
end
对于信息ASP.NET MVC(使用Json.NET)使用C#装饰器属性,它非常优雅:
class Post
{
[JsonPropertyAttribute("title")]
public string Title;
}
我创建了一个要点,展示了如何实现序列化/反序列化:https://gist.github.com/3858908
答案 1 :(得分:1)
Foo.new
对你给它的params散列做的所有操作都是遍历该散列中的键和值。如果密钥为foo_bar
,则会尝试使用值调用foo_bar=
。
如果您定义设置fooBar=
的{{1}}方法,那么您将能够将密钥self.foo_bar
传递给:fooBar
。
少手动,你可以做
Foo.new
为您生成所有额外的访问者。
我不会说最重要的class Foo < ActiveRecord::Base
alias_attribute :fooBar, :foo_bar
end
是一件可怕的事情,但做正确的事情可能很棘手,而且几乎总会有一种更简单的方式或方式让你的意图更清晰。