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

Allow users to globally opt out of automatic lookup #1295

Closed
wants to merge 1 commit into from

Conversation

trek
Copy link
Contributor

@trek trek commented Oct 23, 2015

Adds an option allowing existing applications to opt out of automatic Serialization lookup.

Two use cases where I've already needed this:

  • Existing applications where another serialization system is stomping on the .*Serializer suffix and you need to migrate over to AMS piecemeal
  • Existing applications that have existing public API where they can't change JSON responses and can't change the existing response structure. E.g. if you a Tweet model and want to add a TweetSerializer for controllers under the v2 namespace but not change existing responses for v1 that are created with a bare render json: a_tweet

If this looks good, I'll get a test in.

Closes #1293

@trek trek force-pushed the config-autolookup branch from 1d157eb to 5a71255 Compare October 23, 2015 20:17
@trek trek force-pushed the config-autolookup branch from 5a71255 to 0820d2f Compare October 23, 2015 20:20
@NullVoxPopuli
Copy link
Contributor

@trek for the second example, you could specify a serializer under v1? Maybe I miss the point.

also, for the first point, I think I would be more in favor of configuring teh suffix, rather than opt out of the lookup. The lookup is very powerful. :-)

@@ -5,6 +5,7 @@ The following configuration options can be set on `ActiveModel::Serializer.confi
## General

- `adapter`: The [adapter](adapters.md) to use. Possible values: `:attributes, :json, :json_api`. Default: `:attributes`.
- `automatic_lookup`: Whether serializer should be automatically looked up or manually provided. Default: `true`
Copy link
Member

Choose a reason for hiding this comment

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

@trek (hi!)

actually, you can pass adapter: false in your render (or options[:adapter] = false if you're outside a controller) and it won't look up a serializer or use an adapter.

ref:

  • # True when no explicit adapter given, or explicit appear is truthy (non-nil)
    # False when explicit adapter is falsy (nil or false)
    def use_adapter?
    !(adapter_opts.key?(:adapter) && !adapter_opts[:adapter])
    end
  • if !use_adapter?
    warn 'ActionController::Serialization#use_adapter? has been removed. '\
    "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
    options[:adapter] = false
    end
    serializable_resource = ActiveModel::SerializableResource.new(resource, options)
    if serializable_resource.serializer?
    serializable_resource.serialization_scope ||= serialization_scope
    serializable_resource.serialization_scope_name = _serialization_scope
    begin
    serializable_resource.adapter
    rescue ActiveModel::Serializer::CollectionSerializer::NoSerializerError
    resource
    end
    else
    resource
    end
    end

That should work for you, and would still be useful to include in this PR, to call that out :)

It should also be mentioned in https://github.com/rails-api/active_model_serializers/blob/master/docs/ARCHITECTURE.md, I think

Copy link
Member

Choose a reason for hiding this comment

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

If that's not sufficient, that's the area of the public API that should be affected.. would love to see a code example of what you're trying to do

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Member

Choose a reason for hiding this comment

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

So, #1294 was merged, does that address this issue or should we revert it and continue here?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's unclear if that PR addresses the issue here.
My feeling is that it may be a usage issue (the reason for this PR), but we need more information.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bf4 (hey!)

#1294 addresses 1 of the 2 problem cases. I think the root problem is that automatic lookup is too aggressive of a strategy for larger apps that want to introduce AMS only for new versions of an existing API. It'd be nice – and frankly safer – to opt out globally and opt-in locally in these cases.

Another riff on this PR is to make that an explicit flag on render calls:

render json: photos, use_serializer: true

But I already personally prefer supplying the specific serializer to the render call. Yes, it's repetitive, but removes the "where the heck is this object turning into this JSON?!?" problem.

Copy link
Member

Choose a reason for hiding this comment

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

Right now AMS automatically includes the ActionController::Serialization mixin. What if you could opt out of that and mix it in to controllers as desired. Would that work? (As opposed to passing in adapter: false in most of your controllers)

Copy link
Contributor

Choose a reason for hiding this comment

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

@bf4 are you think that could be an initialization configuration option? something like:

include_action_controller_serialization = true (by default)

?

Copy link
Member

Choose a reason for hiding this comment

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

@trek re:

render json: photos, use_serializer: true

In rails/rails#21496 I have proposed removing use_renderers since it appears never to have been used or tested. Since your suggestion here has a similar name, I was wondering if it might be related to the use_renderers method in the Rails Renderer, or just coincidental

@trek
Copy link
Contributor Author

trek commented Nov 1, 2015

for the second example, you could specify a serializer under v1? Maybe I miss the point.

also, for the first point, I think I would be more in favor of configuring teh suffix, rather than opt out of the lookup. The lookup is very powerful. :-)

v1 in this example (actually several versions in reality) does not use AMS at all nor do we want to through and ensure every every controller specifically opts out. The automatic lookup being always on is very nice for greenfield projects or projects that can go back and update all their calls to render, but makes it painful to adopt AMS into an existing project only for the next API version, leaving the response bodies and code that generates them untouched.

@NullVoxPopuli
Copy link
Contributor

I wonder if it would be beneficial to override the lookup hierarchy?

like, if you have 4 versions of an api, maybe you want to fallback to previous versions, so you don't need to specify all the serializers fro each version?

unless options[:serializer] || options[:each_serializer] || ActiveModel::Serializer.config.automatic_lookup
return resource
end

if !use_adapter?
Copy link
Member

Choose a reason for hiding this comment

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

I suppose you could also make an argument to bring back use_adapter?

Copy link
Member

Choose a reason for hiding this comment

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

(or add ActiveModel::Serializer.config.automatic_lookup as config.implicit_serializers = false which would used probably in the serializable resource

@bf4
Copy link
Member

bf4 commented Nov 10, 2015

What do you think of setting config.implicit_serializers = false ?

@NullVoxPopuli
Copy link
Contributor

I could get behind that, as long as it's documented an well

On Tue, Nov 10, 2015, 4:55 AM Benjamin Fleischer notifications@github.com
wrote:

What do you think of setting config.implicit_serializers = false ?


Reply to this email directly or view it on GitHub
#1295 (comment)
.

@trek
Copy link
Contributor Author

trek commented Nov 24, 2015

Sorry, I don't quite understand the feedback. Are we just bikeshedding the config name or am I missing something?

@bf4
Copy link
Member

bf4 commented Nov 24, 2015

@trek I don't think so.

I did bring up different names, but implementation-wise, I think the switch should be somewhere besides ActionController::Serialization#get_serializer.

I'm thinking there are a few good places to change, not exclusive

  • Turn off implicit lookup, so that resources are passed through unchanged when no serializer is specified. Something like ActiveModel::Serializer.config.implicit_serializers = false (affects: call to ActiveModel::Serializer.serializer_for in SerializableResource)
  • Pass through resource unchanged by setting default adapter to config.adapter = false. Using AMS will then require an explicit adapter option to render in any controller. (impact: SerializableResource#use_adapter?
  • Prevent automatic mixing in of ActionController::Serialization into ActionController::Base with some config, maybe config.action_controller.include = false (impact: the railtie, 2)

Thoughts?

@bf4
Copy link
Member

bf4 commented Nov 26, 2015

Interestingly, this has come up before: #592 (and #611 )

@trek
Copy link
Contributor Author

trek commented Dec 20, 2015

Closing in favor of #1353

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.

AM::S trying to use non-ActiveModel::Serializer seriaizers
4 participants