Подтвердить что ты не робот

As_json не вызывает as_json в ассоциациях

У меня есть модель с данными, которые никогда не должны включаться, когда она отображается как json. Поэтому я применил метод класса as_json для надлежащего поведения. Проблема в том, что другие модели с ассоциациями с этой моделью отображают json, мой пользовательский as_json не вызывается.

class Owner < ActiveRecord::Base
  has_one :dog

  def as_json(options={})
    puts "Owner::as_json"
    super(options)
  end  
end

class Dog < ActiveRecord::Base
  belongs_to :owner

  def as_json(options={})
    puts "Dog::as_json"
    options[:except] = :secret
    super(options)
  end  
end

Загрузка среды разработки (Rails 3.0.3)
ruby-1.9.2-p136: 001 > d = Dog.first
  = > #<Dog id: 1, owner_id: 1, name: "Scooby", secret: "I enjoy crapping everwhere" >
ruby-1.9.2-p136: 002 > d.as_json
Собака:: as_json
 = > { "dog" = > { "id" = > 1, "name" = > "Scooby", "owner_id" = > 1}}
ruby-1.9.2-p136: 004 > d.owner.as_json (: include = > : dog)
Владелец:: as_json
 = > { "owner" = > { "id" = > 1, "name" = > "Shaggy",: dog = > { "id" = > 1, "name" = > "Scooby", "owner_id" = > 1, "secret" = > "Мне нравится обниматься везде" }}}

Спасибо за помощь

4b9b3361

Ответ 1

Это известная ошибка в Rails. (Проблема отмечена закрытой из-за миграции на проблемы Github из предыдущего трекера ошибок, но это все еще проблема с Rails 3.1.)

Ответ 2

Как было отмечено выше, это проблема с базой Rails. Патч rails здесь еще не применяется и кажется хотя бы слегка противоречивым, поэтому я не решаюсь применять его локально. Даже если он применяется как патч обезьяны, это может потенциально осложнить будущие обновления рельсов.

Я по-прежнему рассматриваю RABL, как показано выше, это выглядит полезно. На данный момент я бы предпочел не добавлять в мое приложение другой язык шаблонов. Мои текущие потребности очень малы.

Итак, вот обходной путь, который не требует патча и работает для самых простых случаев. Это работает, когда метод ассоциации as_json, который вы хотите вызвать, выглядит как

def as_json(options={})
  super( <... custom options ...> )
end

В моем случае у меня есть модель Schedule, у которой много Events

class Event < ActiveRecord::Base

  # define json options as constant, or you could return them from a method
  EVENT_JSON_OPTS = { :include => { :locations => { :only => [:id], :methods => [:name] } } }

  def as_json(options={})
    super(EVENT_JSON_OPTS)
  end
end

class Schedule < ActiveRecord::Base
  has_many :events

  def as_json(options={})
    super(:include => { :events => { Event::EVENT_JSON_OPTS } })
  end
end

Если вы следовали указаниям, что в любое время вы :include связываете в своих методах as_json(), вы определяете любые параметры, которые вам нужны в качестве константы в модели, на которую нужно ссылаться, это будет работать для произвольных уровней ассоциаций. ПРИМЕЧАНИЕ Мне нужен только первый уровень ассоциации, настроенный в приведенном выше примере.

Ответ 3

Я столкнулся с той же проблемой. Я хотел, чтобы это работало:

render :json => @favorites.as_json(:include => :location)

Но это не так, я закончил тем, что добавил index.json.erb со следующим:

<% favs = @favorites.as_json.each do |fav| %>
    <% fav["location"] = Location.find(fav["location_id"]).as_json %>
<% end %>
<%= favs.to_json.html_safe %>

Не исправление - просто работа. Я полагаю, вы сделали то же самое.

Ответ 4

Обновление @Джон сказал, что это известная ошибка в Rails. Патч для исправления выглядит следующим образом: at https://github.com/rails/rails/pull/2200. Тем не менее, вы можете попробовать RABL, потому что его сладкий.

Я всегда был разочарован передачей сложного набора опций для создания представлений JSON, которые я хочу. Ваша проблема, с которой я столкнулась с Mongoid в Rails 3.0.9, побудила меня написать шаблоны JSON. Но на самом деле, если вы имеете дело с отношениями или пользовательскими свойствами api, получается, что шаблоны лучше.

Кроме того, работа с разными выходами кажется мне видимым для слоя, поэтому я решил использовать RABL, API templating language.. Это упрощает создание достоверных JSON и включает любые ассоциации или поля.

Не решение проблемы, но лучшее решение для использования.

Ответ 5

Я обнаружил, что serializable_hash работает так же, как вы ожидали, что as_json будет работать, и всегда называется:

  def serializable_hash(options = {})
    result = super(options)
    result[:url] = "http://.."
    result
  end