Ryan Grush
Ryan Grush

Reputation: 2128

How to merge two ActiveRecord queries into one hash and convert to JSON?

I'm using AJAX to get some results, but the problem is I'm querying two separate models and I want to return both and their relationship to one another as one JSON object.

Here's an example of two models I'm trying to link together -

Car
  belongs_to :user

  :id
  :make
  :year
  :user_id

User
  has_many :cars

  :id
  :first_name
  :last_name
  :birthday

I'm trying to get it to look something like this -

{
  1: {
    id: 1,
    first_name: 'Joe'
    last_name: 'Smith'
    cars: {
      23: {
        id: 23,
        make: 'BMW',
        year: 2009,
        user_id: 1
      },
      24: {
        id: 24,
        make: 'Volvo',
        year: 2012,
        user_id: 1
      }
    }
  },
  2: {
    id: 2,
    first_name: 'Bob'
    last_name: 'Johnson'
    cars: {
      35: {
        id: 35,
        make: 'Ford',
        year: 2013,
        user_id: 2
      }
    }
  }
}

Upvotes: 0

Views: 509

Answers (2)

Ryan Grush
Ryan Grush

Reputation: 2128

I ended up using the .as_json I found detailed here to convert ActiveRecord to a plain Ruby hash and passed that hash to the view.

user = User.find(params[:user_id].to_i)

@json = {}
@json[user.id] = user.as_json
@json[user.id]['cars'] = {}

user.cars.each do |car|
  @json[user.id]['cars'][car.id] = car.as_json
end

render json: { status: true, users: @json }

Upvotes: 0

Utsav Kesharwani
Utsav Kesharwani

Reputation: 1745

Create a new (private) method in your controller:

def format_json(users)
  result = {}
  users.each do |user|
    result[user.id] = user.formatted_data
  end
  return result
end

Change the action to return:

users = Users.includes(:cars).where("<your_where_clause>").limit(<n>)
render :json => { :result => format_json(users) }.to_json

app/models/user.rb

class User < ActiveRecord::Base

  def formatted_data
    {
      :id         => self.id,
      :first_name => self.first_name,
      :last_name  => self.last_name,
      :cars       => self.get_car_info
    }
  end

  def get_car_info
    car_info = {}
    self.cars.each do |car|
      car_info[car.id] = car.info
    end
    return car_info
  end
end

app/models/car.rb

class Car < ActiveRecord::Base
  def info
    {
      :id      => self.id,
      :make    => self.make,
      :year    => self.year,
      :user_id => self.user_id
    }
  end
end

Upvotes: 1

Related Questions