ruby-on-railsruby-on-rails-3entitygrape-api

grape each entity in a single file


I want to have multiple classes inside grape entity file, this is the folder structure app/api/proj/api/v2/entities/committees.rb

module PROJ::API::V2::Entities
class Committee < Grape::Entity
expose :id

expose :name, :full_name, :email, :tag, :parent_id

expose :country do |entity, option|
  entity.parent.name if entity.parent.present?
end

# include Urls

private
  def self.namespace_path
    "committees"
  end
end

  class CommitteeWithSubcommittees < CommitteeBase
        # include ProfilePhoto 
        expose :suboffices, with: 'PROJ::API::V2::Entities::CommitteeBase'
      end

and inside the Grape API

present @committees, with: PROJ::API::V2::Entities::Committee

is working. but if I present with

present @committees, with: PROJ::API::V2::Entities::CommitteeList

It is not working. But it works when I move it to a new file named committee_list.rb inside entities.


Solution

  • You seem to be missing some key information from your post because you have not defined a class named CommitteeList or CommitteeBase anywhere. I assume that you have defined them and that you did not supply that code.

    The problem that you're running into has to do with how Rails autoloads classes. There is more information available elsewhere on this, but essentially you should ensure that your class names, modules names, directory names, and file names all match up. The reason that it works when you move your CommitteeList class to its own file is because Rails is able to find the class dynamically.

    I've had to do some guess-work based on what you provided, but you want something that looks like this:

    # app/api/proj/api/v2/entities/committee.rb
    module PROJ::API::V2::Entities
      class Committee < Grape::Entity; end
    end
    
    # app/api/proj/api/v2/entities/committee_base.rb
    module PROJ::API::V2::Entities
      class CommitteeBase; end
    end
    
    # app/api/proj/api/v2/entities/committee_with_subcommittee.rb
    module PROJ::API::V2::Entities
      class CommitteeWithSubcommittee < CommitteeBase; end
    end
    
    # app/api/proj/api/v2/entities/committee_list.rb
    module PROJ::API::V2::Entities
      class CommitteeList < CommitteeBase; end
    end
    

    Note that in this example I have renamed some things; your class names should be singular (committee not committees) and the filenames should match them, but making that change may cause other issues in your app. Generally, you should use singular and not plural.

    I recommend reading the Rails guide entry on constants and autoloading for more detail.

    Updated:

    In your gist you say that you get Uninitialized constant PROJ::API::V2::Entities::CommitteeOffice when you run present @committees, with: PROJ::API::V2::Entities::CommitteeOffice with the following code:

    # app/api/proj/api/v2/entities/committee_base.rb
    module PROJ::API::V2::Entities
      class CommitteeBase < Grape::Entity; 
        expose :id
      end
      class CommitteeOffice < CommitteeBase; 
        expose :name
      end
    end
    

    You get this error because Rails will only look for the class named PROJ::API::V2::Entities::CommitteeBase in the file entities/committee_base.rb. If you prefer to use a single monolithic file for your entity classes, then you must name the above file app/api/proj/api/v2/entities.rb.

    By naming the file app/api/proj/api/v2/entities.rb, it tells Rails "This file contains the module Entities and all its classes."