rails: JSON does not render type attribute for single-table inherited models
I have the following classes participating in an STI hierarchy:
class Server < ActiveRecord::Base
# has database column named "type"
end
class WindowsServer < Server
end
class LinuxServer < Server
end
In my ServersController class, I have code snippet that says:
def show
@server = Server.find(params[:id])
debugger
respond_to do |format|
format.html # show.html.erb
format.json { render json: @server }
end
end
When I examine the @server
object in the debugger, I get the following:
(rdb:43) @server.class.name
"WindowsServer"
(rdb:43) @server.type
"WindowsServer"
(rdb:43) @server
#<WindowsServer id: 5, hostname: "server1", ip_address: "10.1.2.3", description: "", environment_id: 1, type: "WindowsServer", created_at: "2011-11-04 03:38:13", updated_at: "2011-11-04 03:38:13">
(rdb:43) @server.to_json
"{\"created_at\":\"2011-11-04T03:38:13Z\",\"description\":\"\",\"environment_id\":1,\"hostname\":\"server1\",\"id\":5,\"ip_address\":\"10.1.2.3\",\"updated_at\":\"2011-11-04T03:38:13Z\"}"
It’s curious that the type
attribute isn’t included in the JSON string. Sure enough, the type
attribute is also not rendered when I fetch this resource in JSON format:
$ curl http://localhost:3000/servers/5.json
{"created_at":"2011-11-04T03:38:13Z","description":"","environment_id":1,"hostname":"server1","id":5,"ip_address":"10.1.2.3","updated_at":"2011-11-04T03:38:13Z"}
Seems that the type
attribute ought to be included.
About this issue
- Original URL
- State: closed
- Created 13 years ago
- Comments: 15 (5 by maintainers)
I ran into this issue today and found that in my case it was easier to change the structure of the delivered JSON than to change the way the client consumes the response. Inside the model class definition:
The
:methods
option works as wellThe project I work on ran into this issue recently. While @HandyAndyShortStack’s workaround does the trick, I decided to dig into the history a bit to find out what was going on with this one line of code and why this issue is still causing trouble after having been known for years.
:type
(later refactored toself.class.inheritance_column
) is explicitly excluded from the serialized attributes because it was assumed to be always present in the root XML element, and thus redundant.include_root_in_json
property. It was initially false by default, then changed to default to true for Rails 3 in a 2010 commit.include_root_in_json
was set to false by default in Rails 3.1 scaffolding initializer files in a 2011 commit.include_root_in_json
to false in a 2012 commit, removing the need for the initializer scaffolding.Long story short, with include_root_in_json now defaulting to false, this issue has become more annoying and unexpected, since there is no documentation of this specific behavior other than the source code itself. The proper fix would filter out the inheritance_column attribute only when the include_root_in_json attribute is explicitly set to true (which has been deprecated since 2011 and disabled by default since 2012).
Just want to chime in from 2022 and this “feature”, in rails 7, still causes unexpected breakage
It seems it has been like this since the beginning, and I’d argue this is because it’s a server concern related to how the data is stored, and not a client concern - meaning that you don’t need to expose that you use STI for some reason through the serialized object. And I think it’s ok to work this way.
In any case, you should be able to force adding the attribute if you really want it, by giving in the
:only
option. I’m closing here, please let us know if you still find this an issue. Thanks!This works like a charm 🚀
Not sure I’m following the reasoning here. Take the
index
action for example:The output will just be a generic list of servers with no way to differentiate between the windows and linux servers, yeah?