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

Never mutate controller options #1572

Closed
wants to merge 3 commits into from

Conversation

bf4
Copy link
Member

@bf4 bf4 commented Mar 9, 2016

Purpose

Pagination links incorrectly passing options to serializable_hash.

Only the renderer should be passing options to serializable_hash.

It's only working now because we are mutating the controller options which it
later passes to to_json which calls serializable_hash on the adapter.

This PR ensures that we do not mutate controller options, which
exposes failures only in the pagination links.

Changes

  1. Make a (deep) dup of rendering options to pass to SerializableResource
  2. Freezes rendering options (might be undesirable)

    Caveats

  • freezing rendering options might be undesirable in general, and probably is
    not necessary for this fix.

    Related GitHub issues

AMS 0.10.0.rc4 / master

https://github.com/rails-api/active_model_serializers/blob/6b4c8df6fb6bc142ee6a74da51bb26c42a025b3c/lib/active_model_serializers/adapter/json_api.rb

def pagination_links_for(serializer, options)
  PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
end

Those options come from the call to adapter.serializable_hash(options)
which is wrong. They should be passed into the Adapter initializer.

@@ -26,13 +26,13 @@ def serialization_scope
respond_to?(_serialization_scope, true)
end

def get_serializer(resource, options = {})
def get_serializer(resource, serializer_options = {})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thankyou for specifying which options these are. omg

:-)

@NullVoxPopuli
Copy link
Contributor

👍

@bf4 bf4 mentioned this pull request Mar 10, 2016
@groyoh groyoh force-pushed the freeze_controller_options branch from 0bd1eda to f436ab9 Compare March 19, 2016 05:19
@groyoh
Copy link
Member

groyoh commented Mar 19, 2016

Rebased and fixed the tests.

@groyoh groyoh force-pushed the freeze_controller_options branch 2 times, most recently from aad9142 to 094af45 Compare March 19, 2016 05:39
@beauby
Copy link
Contributor

beauby commented Mar 20, 2016

👍

options.fetch(:serialization_context) do
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
options.freeze
serialization_options = options.deep_dup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bf4 I'm not sure if it is good to deep_dup here as it also dup the serializer when present and that made the tests fail. That's why I had to do the workaround below. Is this really needed is your opinion?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't the serializer be a class at this point? How would that be a problem.

I suppose an alternative would be something like strong params where we basically specific which params we want, but that would kill the instance_options behavior.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow there was some issues with the type not being duped properly. Therefore the test failed cause the type method return the wrong value. I didn't dig to much into it though. I can try and spend some more time to figure out why it was duped properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need to dup and freeze the options at all?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking not

On Wed, Mar 30, 2016 at 7:14 AM Yohan Robert [email protected]
wrote:

In lib/action_controller/serialization.rb
#1572 (comment)
:

@@ -56,10 +56,15 @@ def use_adapter?

 [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
   define_method renderer_method do |resource, options|
  •    options.fetch(:serialization_context) do
    
  •      options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
    
  •    options.freeze
    
  •    serialization_options = options.deep_dup
    

Do we actually need to dup and freeze the options at all?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/rails-api/active_model_serializers/pull/1572/files/094af453fe0eb9e8978f6aeec65ec87e22b59a28#r57877815

@bf4
Copy link
Member Author

bf4 commented Mar 21, 2016

@groyoh Thanks for helping clean this up. Great work!

In the future, would you mind doing me a favor and if there's substantial changes, as there are here, to add a commit, rather than amend the existing one? It make it easier to see what's changed. Thanks!

I left a lot of comments here. I've been super swamped lately, and beggars can't be choosers, so I was wondering how you feel about the direction the comments go, code-wise, and if that's something you'd rather talk to me about, wait for me to come back to, or attend to yourself.

Thanks, again! 🌈 ✨

@@ -62,14 +52,14 @@ def setup
publish_at: @publish_at)
@comment1.post = @post
@comment2.post = @post
@error_resource = ModelWithErrors.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved here because it was used by many tests.

@groyoh
Copy link
Member

groyoh commented Mar 21, 2016

@bf4 I actually created multiple commit locally but then squashed them up. I admit that it would have been better to leave it as it was for understanding the changes. I'll try to split them up in multiple commits if possible. I also commented on most of the changes 😉

bf4 added 2 commits March 27, 2016 11:52
- The controller options are now frozen
- The serialization_context is now passed to the adapter via the adapter
  options and no more via as_json
@bf4
Copy link
Member Author

bf4 commented Mar 27, 2016

@groyoh I restored my original commits, 8fe6354543d7ace65c3c7698fac2a9f38f344374 6bd777e29a4c140212e3efc77dd52ee680a80456, and cherry-picked 094af45 for easier review, and rebased on master

@groyoh
Copy link
Member

groyoh commented Mar 27, 2016

Sorry about this 😞

serializer_options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, serializer_options)
serialization_options = options.deep_dup
if options.key?(:serializer)
serialization_options[:serializer] = options[:serializer]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you said there was some weird bug caused by duping the serializer that this fixes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I still haven't figured it out but there were three bugs failling. The resulting JSON API types looked like "some_module_some_class" instead of the values specified via type "post". So I assume when the class was duped the _type wasn't duped properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably remove these lines and run the tests to trigger it.

@@ -128,7 +128,7 @@ def success_document(options)

if is_collection && serializer.paginated?
hash[:links] ||= {}
hash[:links].update(pagination_links_for(serializer, options))
hash[:links].update(pagination_links_for(serializer))
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apparently in the rebase i lost that this was @groyoh 's commit

@bf4
Copy link
Member Author

bf4 commented Apr 11, 2016

Closed by #1647

@bf4 bf4 closed this Apr 11, 2016
@bf4 bf4 deleted the freeze_controller_options branch April 11, 2016 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants