Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to pass :type options when using expose to map to another Grape Entity #82

Closed
linhmtran168 opened this issue Jul 3, 2014 · 8 comments
Labels

Comments

@linhmtran168
Copy link

I have a User Entity like this

class User < Grape::Entity
  expose :id, :username, :email, :fullname, :about, :birthday, :address, :gender
  expose :created_at, :updated_at, :confirmed_at
  expose :billing_address, if: { type: :full }
  expose :shipping_addresses, if: { type: :full }, proc: Proc.new { |user, options| user.shipping_addresses }
end

And a Shop Entity

class Shop < Grape::Entity
  expose :name, :alias, :info, :address
  expose :opening_time, if: { type: :full }
  expose :owner, using: API::Entity::User
end

I cannot find a way to pass the { type: :full } option to expose :owner, using: API::Entity::User. Without that option, the shop entity will only include user entity with fields without { type: :full }.

@linhmtran168
Copy link
Author

Hmm, if I using shop entity like this

present Shop.find(params[:id]), with: API::Entity::Shop, type: :full

Then the shop's owner field is automatically display as a User entity in full. Is is the expected behaviour? What if I only want to present the shop entity in full only?

@dblock dblock added the question label Jul 6, 2014
@dspaeth-faber
Copy link
Contributor

Then the owner field automatically display the shop entity in full. Is is the expected behaviour?

You have in you'r Shop entity also fields exposed with expose :..., if: { type: :full } right?

And now you see all fields of Shop and all fields of User? I think that this is the expected
behaviour. I would use 2 different options. :full_user_info and :full_shop_info.

@phallstrom
Copy link

@linhmtran168 Just ran into this myself. This is working for me (so far).

entities/alert.rb

module Api
  class Entities::Alert < Grape::Entity

    def initialize(object, options = {})
      options.reverse_merge!(short_city: true)
      super
    end

    root 'alerts', 'alert'

    expose :id, documentation: { type: :integer, desc: nil }
    expose :city, using: Entities::City, documentation: {type: 'City' }

  end
end

entities/city.rb

module Api
  class Entities::City < Grape::Entity

    root 'cities', 'city'

    expose :id, documentation: { type: :integer, desc: nil }
    expose :name, documentation: { type: :string, desc: nil }

    expose :latitude, unless: :short_city, documentation: { type: :float, desc: nil }
    expose :longitude, unless: :short_city, documentation: { type: :float, desc: nil }

  end
end

endpoints/alerts.rb

desc "Return list of current user's alerts"
get '', entity: Entities::Alert do
  present current_user.alerts, with: Entities::Alert
end

@dblock
Copy link
Member

dblock commented Aug 26, 2014

@linhmtran168 I am closing this, please feel free to bring it up on the Grape mailing list if none of the solutions pan out.

@dblock dblock closed this as completed Aug 26, 2014
@leods92
Copy link

leods92 commented Sep 26, 2014

I think this should be reopened, it's a missing feature.
It's not currently possible to change variables from an entity.

Another user case that would not be possible because of this missing feature is referencing other objects of the same entity. Since we cannot attribute variables, we'd fall in a circular trap.

@dblock
Copy link
Member

dblock commented Sep 27, 2014

@leods92 Can you open a new issue for each of these, please?

@leods92
Copy link

leods92 commented Sep 28, 2014

@dblock Done! #93 and #94

@daveharris
Copy link

For anyone coming here from Google, I have a different work-around for this, using the OO approach, as hinted in the README (i.e class StatusDetailed < API::Entities::Status).

I wanted 3 slightly different versions, when

  1. embedding in a parent response
  2. the index/list view
  3. the show/detail view

It would be great if I could just do :

class API::Entities::Shop < API::Entities::Base
  expose :owner, using: API::Entity::User, type: :base
end

But I can't, so I used OO to define each use-case, which is arguably better.

api/entities/user.rb

class API::Entities::User < API::Entities::Base
  expose :id
  expose :username
end

api/entities/user_index.rb

class API::Entities::UserIndex < API::Entities::User
  expose :billing_address
end

api/entities/user_show.rb

class API::Entities::UserShow < API::Entities::UserIndex
  expose :shipping_addresses
end

Then I can use them like so:

class API::Entities::Shop < API::Entities::Base
  expose :owner, using: API::Entity::User # base version
end

Then define the API and use with: to declarative the right entity version to use:

class API::V1::Shop < API::V1::Base
  get '/' do
    present Shop.all, with: API::Entities::Shop # returns user.id, user.username
  end
end
class API::V1::User < API::V1::Base
  get '/' do
    present Shop.all, with: API::Entities::UserIndex # returns user.id, user.username, user.billing_address
  end

  params do
    requires :id, type: Integer
  end
  get ':id' do
    present User.find(params[:id]), with: API::Entities::UserShow # returns user.id, user.username, user.billing_address, user.shipping_addresses
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants