0

I am currently using Grape API alongside Rails for our API (Postgresql for the DB). I'm a Junior Dev working full time as a Full Stack Developer so I apologise with my lack of experience with explaining this question.

Currently I am trying to generate a report of 'Staff' and their corresponding 'Addresses'. Now each Staff member can have many addresses.

So what I want to do is make one request to GET multiple Staff with their corresponding Addresses. I still want to retrieve Staff that don't have Addresses so therefore I need a LEFT OUTER JOIN. The problem is that I need conditions on this join. For example, sometimes I may need to send the 'ids' of the Addresses in the GET request so that it will respond with ALL STAFF but only the Addresses I requested. Also there will be other filters for Addresses and Staff such as returning only Staff and Addresses that were active on a certain date.

I am just so unsure how to do this, everything I do doesn't seem to work and I think this is something to do with how Grape API or just rails in general works. When I try a LEFT OUTER JOIN, it still doesn't give me the correct records, and I think this is because in the Grape Entity it is doing something strange on the has_many association when exposing it?

Anyway, I hope I explained this well enough, and if you have a much better approach, please let me know. Maybe doing it in multiple separate requests to get All Staff and the Addresses I need is a better approach.

UPDATE

Sorry about not providing a coding example. I managed to come up with a solution to my problem, but I am not sure if it is a good approach.

 module V2
  module Entities
   class StaffEntity < Grape::Entity
    expose :id, :dob, :first_name, :surname, :email_address,
    :contact_number, :job_title, :emerg_first_name, :emerg_surname,
    :emerg_contact_number, :emerg_relationship

    expose :report_addresses, if: { :include_addresses => true }, as:  
    :addresses, using: V2::Entities::Addresses

    def report_addresses
      addresses = object.addresses
      addresses = addresses.where('addresses.deleted_at IS NULL') unless  options[:date]
      addresses = addresses.where('addresses.created_at <= ? AND (addresses.deleted_at IS NULL OR addresses.deleted_at >= ?)', options[:date].next.midnight, options[:date].next.midnight) if options[:date]
      addresses = addresses.where('addresses.id IN (?)', options[:addresses]) if options[:addresses]
      addresses
    end
   end
  end
 end

I apologize for the messy code in the report_addresses method. I do plan on tidying it up once I get back into work. So basically I moved a lot of the conditional database queries to the Grape Entity instead (and I presume that is the way to do it since Grape Entity will make queries itself to retrieve the nested data?). Any advice on my approach would be appreciated thank you :)

Here is my Grape API responding with the Staff Entity

module V2
  module StaffAPI
  class Staff < GrapeApi
    helpers do
      def get_staff
        if params[:id]
          @staff = Staff.where(:organisation => current_organisation.id).find(params[:id])
                     .includes(:addresses)
        else
          @staff = Staff.where(:organisation => current_organisation.id)
                  .where(:deleted_at => nil)
                  .includes(:current_addresses)
          @staff = @staff.active unless params[:date]
          @staff = @staff.where('staff.created_at <= ? AND (staff.deleted_at IS NULL OR staff.deleted_at >= ?)', params[:date], params[:date]) if params[:date]
          @staff = @staff.where(:id => params[:staff]) if params[:staff]
        end
      end
    end

    before do
      authenticated
    end

    resource :staff do
      params do
        optional :id, type: Integer
        optional :include_addresses, type: Boolean
        optional :include_staff_avatar, type: Boolean
        optional :staff, type: Array[Integer]
        optional :addresses, type: Array[Integer]
        optional :organisations, type: Array[Integer]
        optional :date, type: Date
      end

      get do
        get_staff
        return error!('Staff not found', 404) unless @staff
        present @staff, with: V2::Entities::StaffEntity,
                include_addresses:   params[:include_addresses],
                include_staff_avatar: params[:include_staff_avatar],
                addresses: params[:addresses],
                date: params[:date]
       end
     end
   end
 end
end

I've tried to make the GET request as flexible as possible so you can pass many options to it. But I am not sure if this is a good RESTFUL approach. I figured doing this in ONE Request opposed to getting the nested data in separate API calls was a good solution.

Alan Dragicevich
  • 391
  • 2
  • 5
  • 13
  • 1
    Hi and welcome to Stack Overflow. It's difficult to debug a verbal description of your code. How about you show us what you've tried so far (even if it isn't working) and then we can have a go at altering it to make it do what you need. – Taryn East Sep 15 '16 at 03:21
  • 1
    @TarynEast sorry about. I have updated my post with coding examples. Thank you for the advice. – Alan Dragicevich Sep 16 '16 at 13:15

0 Answers0