1

如何将参数的默认反序列化覆盖为模型对象?换句话说,如何让 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_jsonActiveModel 内部有一个方法,但在Foo.new(params[:foo])运行时不会调用它。

我已经读过好几次了,initialize从模型对象中覆盖是一个糟糕的主意。

4

2 回答 2

2

你给它的 params 散列所做的所有Foo.new事情就是迭代该散列中的键和值。如果键是,foo_bar那么它会尝试foo_bar=使用该值调用。

如果您定义了一个fooBar=设置方法,self.foo_bar那么您将能够将带有键的哈希传递:fooBarFoo.new.

少手动,你可以做到

class Foo < ActiveRecord::Base
  alias_attribute :fooBar, :foo_bar
end

它会为您生成所有额外的访问器。

我不会说压倒一切initialize是一件可怕的事情,但做正确的事情可能很棘手,而且几乎总是有一种更简单的方法或一种让你的意图更清晰的方法。

于 2012-10-05T16:26:28.097 回答
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

于 2012-10-07T13:19:51.923 回答