-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Make Adapters registerable so they are not namespace-constrained #1017
Conversation
a19096d
to
0d617cd
Compare
@joaomdmoura Ready for review! |
klass = ActiveModel::Serializer::Adapter.adapter_class(:json_simple) | ||
assert_nil klass | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to adapter_for file
92df577
to
8da44d7
Compare
@@ -11,6 +13,64 @@ class Adapter | |||
|
|||
attr_reader :serializer | |||
|
|||
# Only the Adapter class has these methods. | |||
# None of the sublasses have them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
8da44d7
to
18e5812
Compare
rebased off of master... |
You'll likely want to take a look at the commit message in cf6a074 |
super | ||
@result | ||
end | ||
class ActiveModel::Serializer::Adapter::FlattenJson < ActiveModel::Serializer::Adapter::Json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the previous style more readable. That's also the syntax (I think) Rails uses internally, perhaps it would be a good idea to align with Rails code style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref: #1017 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruby Style Guide encourages the previous style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even for classes as namespaces? link plz? (besides that it doesn't work in this case, I think it's wrong)
ADAPTER_MAP | ||
end | ||
|
||
# @return Array<adapter_name> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, just me being a little lazy because we're not actually using yardoc (yet?)
a13ffcf
to
9952073
Compare
Per rails-api#1017 (comment) comment by sandstrom in discussion of the inherited hook > I'm thinking that it would be better to register adapters manually, without using the hook, i.e. > have people call ActiveModel::Serializer::Adapter.register directly (perhaps in an initializer). > Possibly, some inspiration can be taken from how ActiveJob adapters are wired[1]. > [1] https://github.com/rails/rails/blob/master/activejob/lib/active_job/queue_adapter.rb
Changes: - Introduce Adapter::get for use by Serializer.adapter - Move Adapter-finding logic from Adapter::adapter_class into Adapter::get Introduced interfaces: - non-inherited methods ```ruby ActiveModel::Serializer::Adapter.adapter_map # a Hash<adapter_name, adapter_class> ActiveModel::Serializer::Adapter.adapters # an Array<adapter_name> ActiveModel::Serializer::Adapter.register(name, klass) # adds an adapter to the adapter_map ActiveModel::Serializer::Adapter.get(name_or_klass) # raises Argument error when adapter not found ``` - Automatically register adapters when subclassing ```ruby def self.inherited(subclass) ActiveModel::Serializer::Adapter.register(subclass.to_s.demodulize, subclass) end ``` - Preserves subclass method `::adapter_class(adapter)` ```ruby def self.adapter_class(adapter) ActiveModel::Serializer::Adapter.get(adapter) end ``` - Serializer.adapter now uses `Adapter.get(config.adapter)` rather than have duplicate logic
e096d22
to
a72b76a
Compare
Per rails-api#1017 (comment) comment by sandstrom in discussion of the inherited hook > I'm thinking that it would be better to register adapters manually, without using the hook, i.e. > have people call ActiveModel::Serializer::Adapter.register directly (perhaps in an initializer). > Possibly, some inspiration can be taken from how ActiveJob adapters are wired[1]. > [1] https://github.com/rails/rails/blob/a11571cec3213753d63ac3e6b4bb3b97fe2594a6/activejob/lib/active_job/queue_adapter.rb#L52-L56
a72b76a
to
6e886c0
Compare
Per rails-api#1017 (comment) comment by sandstrom in discussion of the inherited hook > I'm thinking that it would be better to register adapters manually, without using the hook, i.e. > have people call ActiveModel::Serializer::Adapter.register directly (perhaps in an initializer). > Possibly, some inspiration can be taken from how ActiveJob adapters are wired[1]. > [1] https://github.com/rails/rails/blob/a11571cec3213753d63ac3e6b4bb3b97fe2594a6/activejob/lib/active_job/queue_adapter.rb#L52-L56
@joaomdmoura @bolshakov @sandstrom All cleaned up! |
@bf4 Awesome work on this! While we disagreed on some of the details, I'm overall very positive to making adapters more flexible. ⛵ |
👍 |
Failures on appveyor
|
I was seeing transient failures where adapters may not be registered. e.g. https://travis-ci.org/rails-api/active_model_serializers/builds/77735382 Since we're using the Adapter, JsonApi, and Json classes as namespaces, some of the conventions we use for modules don't apply. Basically, we don't want to define the class anywhere besides itself. Otherwise, the inherited hooks may not run, and some adapters may not be registered. For example: If we have a class Api `class Api; end` And Api is also used as a namespace for `Api::Product` And the classes are defined in different files. In one file: ```ruby class Api autoload :Product def self.inherited(subclass) puts p [:inherited, subclass.name] puts end end ``` And in another: ```ruby class Api class Product < Api def sell_sell_sell! # TODO: sell end end end ``` If we load the Api class file first, the inherited hook will be defined on the class so that when we load the Api::Product class, we'll see the output: ```plain [ :inherited, Api::Product] ``` However, if we load the Api::Product class first, since it defines the `Api` class and then inherited from it, the Api file was never loaded, the hook never defined, and thus never run. By defining the class as `class Api::Product < Api` We ensure the the Api class MUST be defined, and thus, the hook will be defined and run and so sunshine and unicorns. Appendix: The below would work, but triggers a circular reference warning. It's also not recommended to mix require with autoload. ```ruby require 'api' class Api class Product < Api def sell_sell_sell! # TODO: sell end end end ``` This failure scenario was introduced by removing the circular reference warnings in rails-api#1067 Style note: To make diffs on the adapters smalleer and easier to read, I've maintained the same identention that was in the original file. I've decided to prefer ease of reading the diff over style, esp. since we may later return to the preferred class declaration style. with '#' will be ignored, and an empty message aborts the commit.
Per rails-api#1017 (comment) comment by sandstrom in discussion of the inherited hook > I'm thinking that it would be better to register adapters manually, without using the hook, i.e. > have people call ActiveModel::Serializer::Adapter.register directly (perhaps in an initializer). > Possibly, some inspiration can be taken from how ActiveJob adapters are wired[1]. > [1] https://github.com/rails/rails/blob/a11571cec3213753d63ac3e6b4bb3b97fe2594a6/activejob/lib/active_job/queue_adapter.rb#L52-L56
(Thanks to sandstrom for the reference to ActiveJob::QueueAdapters https://github.com/rails/rails/blob/a11571cec3213753d63ac3e6b4bb3b97fe2594a6/activejob/lib/active_job/queue_adapters.rb#L123-L133
4599d9f
to
880f235
Compare
Fixed the build |
Nice work! Really thank you everyone for helping out with this one! |
Make Adapters registerable so they are not namespace-constrained
@@ -62,6 +60,12 @@ def resource_identifier_type_for(serializer) | |||
end | |||
end | |||
|
|||
def add_relationships(resource, name, serializers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why, why, why? :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase foul
Remove legacy method accidentally reintroduced in #1017
* master: (170 commits) Comment private accessor warnings Distinguish options ivar from local; Extract latent Adapter::CachedSerializer Fix or skip appveyor failure on cache expiration Fixing the travis build svg to amster updating version to new release Remove duplicate test helper outside controller use tutorial rubocop-fixes Remove unnecessary parentheses accidentally reintroduced in rails-api#1017. Remove legacy method accidentally reintroduced in rails-api#1017. Update README with nested included association example. Split `serializable_hash` into two methods. Refactor `add_links` in JSONAPI adapter. Fix Markdown to adapters documentation Extended format for JSONAPI `include` option. Updating wording on cache expiry in README Fix typo in fieldset exception Fixed indentation in readme under 'using without render' Documentation for serializing resources without render Get rid of unnecessary instance variables, and implied dependencies. ... Conflicts: lib/active_model/serializer/adapter/json_api.rb
Changes:
Gemfile.local
for gems not in the gemspec or Gemfile e.g.pry-byebug
(which was my usecase).Background Ref:
Introduced interfaces:
::adapter_class(adapter)
Adapter.lookup(config.adapter)
rather than haveduplicate logic
TODO
Test
TO CONSIDER
TODO in future PR:
Adapter
to module (backwards compatible public methods) and makeAdapter::Base
orAdapter::AbstractClass
Full commit message from cf6a074