Tom Rossi
Tom Rossi

Reputation: 12066

Grouping ActiveRecord objects and outputting to JSON

I am wondering how I can make this work. Assuming I have a model of Project that belongs_to a Client. I want to output those particular projects to JSON, but they need to be grouped by their client. I thought this would work:

@projects.group_by(&:client).to_json

That ALMOST works, except the to_json method isn't calling .to_json on the client, so for the client you get this in your JSON:

"#<Client:0x1051d4fb0>":[{ "project":{"name":"My Only Project", "client_id":1}}]

But I really need it like this:

{"client":{"name":"Home Workers Unite", "id":1, "projects":[{"name":"My Only Project","client_id":1}]}}

Any help is appreciated!

Upvotes: 2

Views: 1999

Answers (3)

rubish
rubish

Reputation: 10907

As already told by @LarryK, the json you want as out put is not a valid json. In json keys can only be strings unlike ruby which can has objects as keys. Also, I would suggest that the json response be more like following:

{clients: [
    {
      "name":"Home Workers Unite", 
      "id":1,
      "projects": [
        {"name":"My First Project", "id":1},
        {"name":"My Second Project", "id":2}
      ]
    }
  ]
}

You already have projects available with you. You also have the code to group them by client, but a simple to_json on the resulting hash would not be suitable here. You would need to manipulate the grouped response further to be able to directly use to_json:

results = {clients: []}
@projects.group_by(&:client).each do |client, projects|
  results[:clients] << {
    id: client.id,
    name: client.name
    projects: projects
  } 
end
results.to_json

This is ruby/rails version of the solution. However if you have a json heavy application, I would suggest using some gem(jbuilder, rabl, or any other) to create the desired responses.

PS: code is not tested

Upvotes: 3

Larry K
Larry K

Reputation: 49104

The json in your orig post is not valid json since you don't have a property name for the array of projects.

Look into the acts_as_api suggestion from Murifox and other api techniques from railscasts--he just did one recently.

If your api user only wants one client at a time, you can use a json structure such as:

{client: {"name":"Home Workers Unite", "id":1},
 projects: [
      {"name":"My Only Project", "client_id":1}
           ]
}

Or you can send a subset (or all) of the needed client and project info:

{clients: [
   {"name":"Home Workers Unite", "id":1},
   {"name":"Factory Workers Unite", "id":2},
          ],
 projects: [
      {"name":"My Only Project", "client_id":1},
      {"name":"Project 2", "client_id":2},
      {"name":"Project 3", "client_id":2}
           ]
}

Benefit: fewer roundtrips from the server to the api client.

Upvotes: 0

MurifoX
MurifoX

Reputation: 15089

I recommend you to take a look at the gem acts_as_api. It makes it very easy to manipulate your objects as JSON.

Upvotes: 1

Related Questions