1

I have two objects, an @article and a @profile. Article is a model and @profile is a Struct. I'd like to end up with some JSON that looks like this:

{
    "article": {
        "title": "this is a title",
        "author": "Author McAuthor",
        "profile": {
            "first_name": "Bobby",
            "last_name": "Fisher"
        }
    }
}

As of now, I can just manually create this by doing something like:

@json = { article: { title: @article.title, author: @article.author, profile: { first_name: @profile.first_name, last_name: @profile.last_name } }}

I feel like building the json object this way is sorta crude, also, every time I change the author model, I might have to change this code. It would be great if I could find an easier way to build these json objects without having to do so manually... Any help? Thanks!

8
  • Build whatever ruby structure you like (consisting of arrays and hashes), and then use .to_json on it. But then, I just found at least one person does not like that - blog.gomiso.com/2011/05/16/… Commented Feb 11, 2013 at 23:33
  • you mind being a bit more specific? Commented Feb 11, 2013 at 23:34
  • If you have a Ruby variable, a has for example, you can call variable.to_json and get the json string as a result. Rails adds a to_josn method on Object (all it does is call ActiveSupport::JSON.encode(self, options)). See api.rubyonrails.org, enter to_json in the search box. Commented Feb 11, 2013 at 23:40
  • i am aware of those methods. i am trying to nest one object inside another object in json without building the strings manually, then add new attributes to where i'm building the json string every time the objects update. Commented Feb 11, 2013 at 23:43
  • It's better to override as_json: jonathanjulian.com/2010/04/rails-to_json-or-as_json Commented Feb 11, 2013 at 23:43

2 Answers 2

2

In addition to shioyama's correct answer, you can use rabl to craft your JSON objects, similar to how ERB works for views.

For example, you would create a 'view', say, index.rabl. It would look like:

collection @articles
attributes :author, :title
child(:profile) { attributes :first_name, :last_name }
Sign up to request clarification or add additional context in comments.

3 Comments

+1 This is what I was going to say. The rabl gem builds your JSON API using a standard Rails view. This gives you the ultimate flexibility and avoids the tendency to couple your model schema to your API.
@Sean Hill curious, if i wanted to create that child(:profile) but then create a custom attribute called "profile_views" how would i do that?
Then you would do child(:profile) { attributes :first_name, :last_name; node(:profile_views) { |profile| profile.profile_views } }, assuming that profile_views is a method on the profile instance.
2

Rails serializes objects in two steps, first by calling as_json to create the object to be serialized, then by calling to_json to actually create the JSON string.

Generally, if you want to customize how your models are represented in JSON, it's best to override as_json. Assuming your profile struct is a virtual attribute (i.e. defined with attr_accessor, not saved in the db), you could do this in your Article model:

def as_json(options = {})
  super((options || {}).merge({
    :methods => :profile
  }))
end

Hope that helps. See also:

4 Comments

Updated my answer to pass through any options to super.
+1 thanks @shioyama. i will look into that. \@profile is not a virtual attribute, but perhaps it should be?
so this code is saying that we are going to merge the result of the method profile into the article json?
It says we are going to merge the key/value pair :methods => :profile into whatever options are passed in to as_json when it is caled. The :methods option is used to declare any method return values you want to include in your JSON. So if you have a method profile which returns an object, then it will be included and converted to JSON using to_json. Hope that makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.