-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Block syntax for associations. #1311
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,8 @@ module Associations | |
| DEFAULT_INCLUDE_TREE = ActiveModel::Serializer::IncludeTree.from_string('*') | ||
|
|
||
| included do |base| | ||
| class << base | ||
| attr_accessor :_reflections | ||
| end | ||
| base.class_attribute :_reflections | ||
| base._reflections ||= [] | ||
|
|
||
| extend ActiveSupport::Autoload | ||
| autoload :Association | ||
|
|
@@ -29,58 +28,44 @@ class << base | |
|
|
||
| module ClassMethods | ||
| def inherited(base) | ||
| base._reflections = self._reflections.try(:dup) || [] | ||
| super | ||
| base._reflections = _reflections.dup | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why was this a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so any class that inherits
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, including
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh ok, so you're setting
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. depending if the parent class has some reflections already or not
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused. Sorry. Can you summarize?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Module
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear, those changes are mainly (if not only) cosmetic, in order to be consistent with how we deal with inheritance of class attributes all around, they're not necessary for this PR. |
||
| end | ||
|
|
||
| # @param [Symbol] name of the association | ||
| # @param [Hash<Symbol => any>] options for the reflection | ||
| # @param [Block] optional block to customize value of the reflection | ||
| # @return [void] | ||
| # | ||
| # @example | ||
| # has_many :comments, serializer: CommentSummarySerializer | ||
| # | ||
| def has_many(name, options = {}) | ||
| associate HasManyReflection.new(name, options) | ||
| def has_many(name, options = {}, &block) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we keep the |
||
| _reflections << HasManyReflection.new(name, options, block) | ||
| end | ||
|
|
||
| # @param [Symbol] name of the association | ||
| # @param [Hash<Symbol => any>] options for the reflection | ||
| # @param [Block] optional block to customize value of the reflection | ||
| # @return [void] | ||
| # | ||
| # @example | ||
| # belongs_to :author, serializer: AuthorSerializer | ||
| # | ||
| def belongs_to(name, options = {}) | ||
| associate BelongsToReflection.new(name, options) | ||
| def belongs_to(name, options = {}, &block) | ||
| _reflections << BelongsToReflection.new(name, options, block) | ||
| end | ||
|
|
||
| # @param [Symbol] name of the association | ||
| # @param [Hash<Symbol => any>] options for the reflection | ||
| # @param [Block] optional block to customize value of the reflection | ||
| # @return [void] | ||
| # | ||
| # @example | ||
| # has_one :author, serializer: AuthorSerializer | ||
| # | ||
| def has_one(name, options = {}) | ||
| associate HasOneReflection.new(name, options) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| # Add reflection and define {name} accessor. | ||
| # @param [ActiveModel::Serializer::Reflection] reflection | ||
| # @return [void] | ||
| # | ||
| # @api private | ||
| # | ||
| def associate(reflection) | ||
| self._reflections = _reflections.dup | ||
|
|
||
| define_method reflection.name do | ||
| object.send reflection.name | ||
| end unless method_defined?(reflection.name) | ||
|
|
||
| self._reflections << reflection | ||
| def has_one(name, options = {}, &block) | ||
| _reflections << HasOneReflection.new(name, options, block) | ||
| end | ||
| end | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,7 @@ class Serializer | |
| # | ||
| # So you can inspect reflections in your Adapters. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is a reflection?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh. ha. didn't see there was more. thanks |
||
| # | ||
| Reflection = Struct.new(:name, :options) do | ||
| Reflection = Struct.new(:name, :options, :proc) do | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer |
||
| # Build association. This method is used internally to | ||
| # build serializer's association by its reflection. | ||
| # | ||
|
|
@@ -40,7 +40,11 @@ class Serializer | |
| # @api private | ||
| # | ||
| def build_association(subject, parent_serializer_options) | ||
| association_value = subject.send(name) | ||
| association_value = if proc.nil? | ||
| subject.object.send(name) | ||
| else | ||
| subject.instance_eval(&proc) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need a design that requires us to instance_eval? |
||
| end | ||
| reflection_options = options.dup | ||
| serializer_class = subject.class.serializer_for(association_value, reflection_options) | ||
|
|
||
|
|
@@ -54,7 +58,7 @@ def build_association(subject, parent_serializer_options) | |
| reflection_options[:virtual_value] = association_value.try(:as_json) || association_value | ||
| end | ||
| elsif !association_value.nil? && !association_value.instance_of?(Object) | ||
| reflection_options[:virtual_value] = association_value | ||
| reflection_options[:virtual_value] = association_value.try(:as_json) || association_value | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is there a try here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency with the way we handle collections for which we can't find serializers.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how do you mean? what scenarios are those?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When doing has_many :blah do
[ { id: 3, type: 'blah' }, {...} ]
endor belongs_to :blah do
{ id: blah, type: 'blah' }
end
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you write some comments about why try is being used and a quick blurb about when association_value might not have thanks ;-)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need the |
||
| end | ||
|
|
||
| Association.new(name, serializer, reflection_options) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,12 +62,10 @@ module Spam; end | |
| attributes :id, :title, :body | ||
|
|
||
| has_many :comments | ||
| belongs_to :blog | ||
| belongs_to :author | ||
|
|
||
| def blog | ||
| belongs_to :blog do | ||
| Blog.new(id: 999, name: 'Custom blog') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this mean?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. n/m it just looks weird to create an artificial association, but that's pre-existing |
||
| end | ||
| belongs_to :author | ||
|
|
||
| def custom_options | ||
| instance_options | ||
|
|
@@ -124,9 +122,7 @@ def slug | |
|
|
||
| LocationSerializer = Class.new(ActiveModel::Serializer) do | ||
| cache only: [:place], skip_digest: true | ||
| attributes :id, :lat, :lng | ||
|
|
||
| belongs_to :place | ||
| attributes :id, :lat, :lng, :place | ||
|
|
||
| def place | ||
| 'Nowhere' | ||
|
|
@@ -212,13 +208,11 @@ def self.root_name | |
| VirtualValueSerializer = Class.new(ActiveModel::Serializer) do | ||
| attributes :id | ||
|
|
||
| has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }] | ||
| has_one :maker, virtual_value: { id: 1 } | ||
|
|
||
| def reviews | ||
| has_many :reviews do | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. much cleaner than
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, plus I'm not sure
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even better! |
||
| [{ id: 1 }, { id: 2 }] | ||
| end | ||
|
|
||
| def maker | ||
| has_one :maker do | ||
| { id: 1 } | ||
| end | ||
| 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.
I don't think we want this to be instance readable/writable? Do we want these to be inheritable?
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.
re: inhertiable, yes, oops