Including "type" attribute in json respond_with Rails 3.1
Asked Answered
D

4

11

It seems that when returning an object containing a "type" attribute as JSON from a Rails 3.1 application, the "type" attribute is not included. Assume I have the following:

A model with corresponding STI table Animal. Models Cat, Dog and Fish that inherit Animal.

When returning an Animal via JSON, I wish to include the "type" column, but this is not happening:

jQuery.ajax("http://localhost:3001/animals/1", {dataType: "json"});

yields:

responseText: "{"can_swim":false,"created_at":"2012-01-20T17:55:16Z","id":1,"name":"Fluffy","updated_at":"2012-01-20T17:55:16Z","weight":9.0}"

It seems like this is a problem with to_json:

bash-3.2$ rails runner 'p Animal.first.to_yaml'
"--- !ruby/object:Cat\nattributes:\n  id: 1\n  type: Cat\n  weight: 9.0\n  name: Fluffy\n  can_swim: false\n  created_at: 2012-01-20 17:55:16.090646000 Z\n  updated_at: 2012-01-20 17:55:16.090646000 Z\n"

bash-3.2$ rails runner 'p Animal.first.to_json'
"{\"can_swim\":false,\"created_at\":\"2012-01-20T17:55:16Z\",\"id\":1,\"name\":\"Fluffy\",\"updated_at\":\"2012-01-20T17:55:16Z\",\"weight\":9.0}"

Does anyone know the reasoning behind this behavior, and how to override it?

Demandant answered 20/1, 2012 at 18:3 Comment(0)
H
6

Override the as_json method. It's used by to_json in order to produce the output. You can do something like:

def as_json options={}
 {
   id: id,
   can_swim: can_swim,
   type: type
 }
end
Haeres answered 20/1, 2012 at 18:7 Comment(2)
This seems like a nice compromise to reduce redundancy: def as_json(options = {}) { type: type }.merge super endDemandant
You're welcome. I like to override as_json because I know how I'm actually converting my objects to JSON and I'm converting only what I really need to convert.Haeres
H
19

This is what i did. It just adds the missing type to the result set

  def as_json(options={})
    super(options.merge({:methods => :type}))
  end
Hardesty answered 26/9, 2013 at 15:56 Comment(0)
H
6

Override the as_json method. It's used by to_json in order to produce the output. You can do something like:

def as_json options={}
 {
   id: id,
   can_swim: can_swim,
   type: type
 }
end
Haeres answered 20/1, 2012 at 18:7 Comment(2)
This seems like a nice compromise to reduce redundancy: def as_json(options = {}) { type: type }.merge super endDemandant
You're welcome. I like to override as_json because I know how I'm actually converting my objects to JSON and I'm converting only what I really need to convert.Haeres
N
1

For me, in Rails 2.3.12, the above does not work.

I can (in my Model of course) do something like this:

class Registration < ActiveRecord::Base

  def as_json(options={})
    super(options.merge(:include => [:type]))
  end

end

But that causes to_json to throw an error like this:

NoMethodError: undefined method `serializable_hash' for "Registration":String

I've worked around this with this, which is punches this method onto the object I want to export

class Registration < ActiveRecord::Base

  def as_json(options={})
    super(options.merge(:include => [:type]))
  end

  def type
    r  = self.attributes["type"]
    def r.serializable_hash(arg)
      self
    end
    r
  end
end

So on my app, I've put this into a mixin:

module RailsStiModel
  # The following two methods add the "type" parameter to the to_json output.
  # see also:
  # https://mcmap.net/q/967688/-including-quot-type-quot-attribute-in-json-respond_with-rails-3-1/15293715#15293715
  def as_json(options={})
    super(options.merge(:include => [:type]))
  end

  def type
    r  = self.attributes["type"]
    def r.serializable_hash(arg)
      self
    end
    r
  end
end

And now in my model class(es), I add:

include RailsStiModel
Nonoccurrence answered 8/3, 2013 at 12:10 Comment(0)
R
0

Here is my solution which can keep the original feature of as_json.

def as_json(options={})
  options = options.try(:clone) || {}
  options[:methods] = Array(options[:methods]).map { |n| n.to_sym }
  options[:methods] |= [:type]

  super(options)
end
Rockfish answered 8/7, 2013 at 3:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.