Question

Currently my data structure includes Appointments, which belong to Contracts. I need to access list of all contracts along with the contracts' appointments (appointments filtered by field_rep).

def index # ContractsController
    rep_name = # …
    render json: Contract.all.map { |c| c.as_json_with_appointments_for_rep(rep_name) }
end

# Contract.rb
def as_json_with_appointments_for_rep(rep_name)
    appts = Appointment.where("contract_id=#{ self.id } AND rep_name='#{ rep_name }'")
    self.as_json.merge({ appointments: appts })
end
def as_json(options = {})
    super(except: [:created_at, :updated_at, :user_id]).merge({ dropoff_date: self.dropoff_date, items: self.active_items, user: self.user })
end

Here, every contract requires a separate database call to get its appointments, resulting in horrible response times.

I'm thinking I'll INNER JOIN appointments and contracts on Appointments.contract_id = Contracts.id but I'm not sure how to bundle the Appointment results into a nested hash in the result. Current output looks like

[ // List of contracts
  {
    'id': 1,
    'appointments': [
      {
        'id': 1,
        // … other appointment fields
      },
      // … More appointments
    ]
  },
  // … More contracts
]

The client is built to handle a contract with no appointments (if a contract has no appointments assigned to the provided rep). Currently using PostgreSQL on Heroku

Was it helpful?

Solution

Seems like you need to to use an outer join. Rails implements this with includes or eager_load.

In your case you can have

@contracts = Contract.a_desired_scope.includes(:appointments)

then

@contracts.to_json

will only require one query to fetch all contracts with their relevant appointments.

instead of to_json you can use whatever iterating method you want, without affecting the number of queries.

In your case you can have a to_json method for each model

#apointment.rb

def to_json
  desired_attributes_hash.to_json
end

and

#contract.rb

def to_json
  {
   id: id
   apointments: apointments.map(&:to_json)
  }
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top