Update:
This issue was not properly explored. The real issue lies within render :json.
The first code paste in the original question will yield the expected result. However, there is still a caveat. See this example:
render :json => current_user
is NOT the same as
render :json => current_user.to_json
That is, render :json will not automatically call the to_json method associated with the User object. In fact, if to_json is being overridden on the User model, render :json => @user will generate the ArgumentError described below.
summary
# works if User#to_json is not overridden
render :json => current_user
# If User#to_json is overridden, User requires explicit call
render :json => current_user.to_json
This all seems silly to me. This seems to be telling me that render is not actually calling Model#to_json when type :json is specified. Can someone explain what’s really going on here?
Any genii that can help me with this can likely answer my other question: How to build a JSON response by combining @foo.to_json(options) and @bars.to_json(options) in Rails
Original Question:
I’ve seen some other examples on SO, but I none do what I’m looking for.
I’m trying:
class User < ActiveRecord::Base
# this actually works! (see update summary above)
def to_json
super(:only => :username, :methods => [:foo, :bar])
end
end
I’m getting ArgumentError: wrong number of arguments (1 for 0) in
/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
Any ideas?
You are getting
ArgumentError: wrong number of arguments (1 for 0)becauseto_jsonneeds to be overridden with one parameter, theoptionshash.Longer explanation of
to_json,as_json, and rendering:In ActiveSupport 2.3.3,
as_jsonwas added to address issues like the one you have encountered. The creation of the json should be separate from the rendering of the json.Now, anytime
to_jsonis called on an object,as_jsonis invoked to create the data structure, and then that hash is encoded as a JSON string usingActiveSupport::json.encode. This happens for all types: object, numeric, date, string, etc (see the ActiveSupport code).ActiveRecord objects behave the same way. There is a default
as_jsonimplementation that creates a hash that includes all the model’s attributes. You should overrideas_jsonin your Model to create the JSON structure you want.as_json, just like the oldto_json, takes an option hash where you can specify attributes and methods to include declaratively.In your controller,
render :json => ocan accept a string or an object. If it’s a string, it’s passed through as the response body, if it’s an object,to_jsonis called, which triggersas_jsonas explained above.So, as long as your models are properly represented with
as_jsonoverrides (or not), your controller code to display one model should look like this:The moral of the story is: Avoid calling
to_jsondirectly, allowrenderto do that for you. If you need to tweak the JSON output, callas_json.