如何覆盖params对模型对象的默认反序列化?

时间:2012-10-05 16:11:13

标签: ruby-on-rails ruby ruby-on-rails-3

如何覆盖对模型对象的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这是一个糟糕的主意。

2 个答案:

答案 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 是一件可怕的事情,但做正确的事情可能很棘手,而且几乎总会有一种更简单的方式或方式让你的意图更清晰。