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

Fix or workaround for duplicate exposure caveat? #56

Closed
nickls opened this issue Feb 13, 2014 · 13 comments
Closed

Fix or workaround for duplicate exposure caveat? #56

nickls opened this issue Feb 13, 2014 · 13 comments
Labels

Comments

@nickls
Copy link

nickls commented Feb 13, 2014

I'm looking to expose using different entities if a user is anonymous or not:

class MediaEntity < Grape::Entity
  expose :id
  expose :user, using: Entities::UserEntity, if: lambda { |object, options| object.anonymous == false }
  expose :user, using: Entities::AnonymousUserEntity, if: lambda { |object, options| object.anonymous == true }
end

present :data, media, with: MediaEntity

This doesn't work as you documented in the caveat section. Is there a good workaround?

Also, do you have a solution in mind for this?

@dblock
Copy link
Member

dblock commented Feb 13, 2014

That would be a bug. Start by writing a test that demonstrates the problem.

@dblock dblock added the bug? label Feb 13, 2014
@nickls
Copy link
Author

nickls commented Mar 15, 2014

Added proof of concept here:
https://gist.github.com/nickls/9560205

Please let me know if you have any questions.

@dblock
Copy link
Member

dblock commented Mar 15, 2014

@nickls Can you please confirm whether this is fixed on HEAD?

@donbobka
Copy link

This issue documented in caveats.
I wrote a failing test here donbobka/grape-entity@b73d3d9

Result

Failures:

  1) Grape::Entity class methods .expose when same exposures with different options using and if should generate right result
     Failure/Error: ]
       expected: [{:media=>{:sound_file=>"sound_file"}}, {:media=>{:photo_file=>"photo_file"}}]
            got: [{}, {:media=>{:photo_file=>"photo_file"}}] (using ==)
       Diff:
       @@ -1,2 +1,2 @@
       -[{:media=>{:sound_file=>"sound_file"}}, {:media=>{:photo_file=>"photo_file"}}]
       +[{}, {:media=>{:photo_file=>"photo_file"}}]

     # ./spec/grape_entity/entity_spec.rb:325:in `block (5 levels) in <top (required)>'

Workaround:
Use different names for exposures with option as and pass a representable object in block

class MediaEntity < Grape::Entity
  expose :media_sound, as: :media, using: SoundEntity, if: lambda { |object, _| object.sound? } { |object, _| object.media }
  expose :media_photo, as: :media, using: PhotoEntity, if: lambda { |object, _| object.photo? } { |object, _| object.media }
end

@Morred
Copy link

Morred commented Apr 22, 2015

@nickls @donbobka @dblock Is this still being worked on, or can I help in any way? I ran into exactly the same problem today and would love to see this working (unless there's a specific reason for the exposures overwriting each other).

@dblock
Copy link
Member

dblock commented Apr 22, 2015

Would love a pull request that addresses the spec failure mentioned above.

@Morred
Copy link

Morred commented Apr 23, 2015

Cool, I'll see what I can do.

@Morred
Copy link

Morred commented Apr 23, 2015

I took @donbobka's test and adapted it a bit: https://github.com/Morred/grape-entity/tree/double-exposure

The test fails, and what happens is technically exactly what you're describing in the caveat section of the Readme, the second exposure overwrites the first exposure. Don't know if this is considered a bug (because you do document it in the Readme), but it would certainly be a lot more convenient if this did not happen.

@Morred
Copy link

Morred commented Apr 29, 2015

Completely forgot the pull request >.< It's there now.

@marshall-lee
Copy link
Member

I don't see a bug here. Both https://gist.github.com/nickls/9560205 and #124 demonstrate documented behavior: exposure with the same name overwrite previously defined.

However, It would be good to not overwrite them. I think Grape::Entity's DSL for exposures is very similar to a regular ruby code so principle of least surprise says us that DSL is expected to behave as a regular Ruby code. For example:

# Grape::Entity:
expose :a
expose :a, if: -> (object, options) { object.some_condition? }

# Regular ruby code:
expose object.a
expose object.a if object.some_condition?

Looks similar, right?

I definitely want this feature to be implemented and I think I could do it. But it will break backward compatibility (i.e. that caveat in README about double exposures will gone) and it requires big changes in code.

So what should be done in examples:

expose :x, using: E1
expose :x, using: E2

Here x should be exposed using E2.

expose :x, using: E1, if: -> { some_condition? }
expose :x, using: E2

Here x should be exposed using E2 — no matter what the value of some_condition? is.

expose :x, using: E1
expose :x, using: E2, if: -> { some_condition? }

Here x should be exposed using E2 iff some_condition? is true, otherwise it should be exposed using E1.

expose :x, using: E1, if: -> { first_condition? }
expose :x, using: E2, if: -> { second_condition? }

Here:

  • x should be exposed using E1 iff first_condition? is true and second_condition? is false.
  • x should be exposed using E2 iff second_condition? is true — no matter what the value of first_condition? is.
  • x should not be exposed at all iff first_condition? and second_condition? are both false.

I could write detailed failing specs for this and try to construct an implementation.

@dblock
Copy link
Member

dblock commented Jul 17, 2015

@marshall-lee, I think of expose as a method. If I make two method calls I expect it to be called twice, so I think this is the bug, especially if we think of it behaving like Ruby code. No?

@marshall-lee
Copy link
Member

@dblock

Yes and I like it.

I just said it's not a bug but a documented caveat. Double exposure overwrites previously defined — not matter they're conditional or not. And since it's documented, implementing it the right way is not backward compatible. Though I think that it would be better not being compatible with quirky behavior :)

@dblock
Copy link
Member

dblock commented Jul 18, 2015

I am ok with breaking backward compatibility here as long as we have an upgrade path for someone who wants that behavior.

marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 21, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56: now `exposures` is not a hash table but an array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - For ones who want previous rewriting behavior a `rewrite` option
   for `exposure` is introduced.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 21, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56: now `exposures` is not a hash table but an array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - For ones who want previous rewriting behavior a `rewrite` option
   for `exposure` is introduced.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 22, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56: now `exposures` is not a hash table but an array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - For ones who want previous rewriting behavior a `rewrite` option
   for `exposure` is introduced.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 23, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56: now `exposures` is not a hash table but an array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`
 - Fixes ruby-grape#152
 - Fixes ruby-grape#153
 - Fixes ruby-grape#155
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 23, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56: now `exposures` is not a hash table but an array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`
 - Fixes ruby-grape#152
 - Fixes ruby-grape#153
 - Fixes ruby-grape#155
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 24, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.

Version is bumbed to 0.5.0.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 24, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.

Version is bumbed to 0.5.0.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 24, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.

Version is bumbed to 0.5.0.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 27, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 27, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 27, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Jul 27, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 20-30%.
marshall-lee added a commit to marshall-lee/grape-entity that referenced this issue Aug 2, 2015
This one reaches many goals at once:

 - Fixes ruby-grape#56.
 - `exposures` hash table is removed and substituted with
   `root_exposures` array.
 - Due to previous point, tree structure `nested_exposures` based on
   flat hash table with keys like `root_node__node__node` is removed
   because now double exposures don't rewrite previously defined
   so such tree structure is simply incorrect.
   `NestingExposure` with an array of children is introduced instead.
 - Ones who want an old rewriting behavior should manually `unexpose`.
 - Fixes ruby-grape#112.
 - Fixes ruby-grape#149: runtime `options` are now wrapped in an `Options` object.
 - Fixes ruby-grape#150: see new `spec/grape_entity/exposure_spec.rb`.
 - Fixes ruby-grape#152.
 - Fixes ruby-grape#153.
 - Fixes ruby-grape#155.
 - Fixes ruby-grape#156.
 - All exposure configuration and exposing strategies are extracted to
   the separate classes.
 - `key_for`, `name_for` internal methods are removed.
 - Much of the overhead is gone so performance is increased by 15-30%.
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

5 participants