-
Notifications
You must be signed in to change notification settings - Fork 420
add optional attributes #66
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 |
---|---|---|
|
@@ -12,6 +12,7 @@ module SerializationCore | |
included do | ||
class << self | ||
attr_accessor :attributes_to_serialize, | ||
:optional_attributes_to_serialize, | ||
:relationships_to_serialize, | ||
:cachable_relationships_to_serialize, | ||
:uncachable_relationships_to_serialize, | ||
|
@@ -73,13 +74,21 @@ def links_hash(record, params = {}) | |
end | ||
|
||
def attributes_hash(record, params = {}) | ||
attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash| | ||
attributes = attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash| | ||
attr_hash[key] = if method.is_a?(Proc) | ||
method.arity == 1 ? method.call(record) : method.call(record, params) | ||
else | ||
record.public_send(method) | ||
end | ||
end | ||
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. If we had a single "attribute definition", then we can extract the evaluation into a separate method, e.g.: attributes_to_serialize.each_with_object({}) do |(key, definition), attr_hash|
inject_attribute(record, params, attr_hash, key, definition)
end
...
def inject_attribute(record, serialization_params, output_hash, key, definition)
if_proc = definition[:if]
include_key = if_proc ? if_proc.call(record, serialization_params) : true
if include_key
output_hash[key] = ...
end
end Something like that. In general it just seems like it would be nice to have a single function that says "given a record, an output hash, and an attribute definition, apply the attribute definition to the record and adjust the output hash accordingly". |
||
|
||
self.optional_attributes_to_serialize = {} if self.optional_attributes_to_serialize.nil? | ||
optional_attributes_to_serialize.each do |key, details| | ||
method_name, check_proc = details | ||
attributes[key] = record.send(method_name) if check_proc.call(record) | ||
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. @andyjeffries couldn't this be 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. Yep, that's a nice touch too. |
||
end | ||
|
||
attributes | ||
end | ||
|
||
def relationships_hash(record, relationships = nil, params = {}) | ||
|
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 think it will be more maintainable if we put all attributes into a single
attributes_to_serialize
list, rather than splitting them up. It will help to have one single code path to enumerate the attributes and to evaluate them, as we continue to evolve this and add more option parameters besidesif
. Theif
check should be part of the evaluation process.Maybe the value for each key of
attributes_to_serialize
should be a hash with{ method_name: ..., block: ..., params: ... }
. Or an actualAttributeDefinition
class. That way we can have a single list of attributes with a common structure that defines how to evaluate it.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.
Good points. I like the idea of the
AttributeDefinition
class if it's to have a defined structure. Using a hash and expecting it to be of a particular form can get fragile as multiple people continue iterating on it (in my opinion).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.
@TrevorHinesley Yeah, in fact, the
AttributeDefinition
class can be the one with the serialization method:(EDIT: extracting the attribute evaluation away from the serializer itself may make the ability to define custom attribute methods on the serializer (#49) harder, so let's take that into account too.)
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.
@christophersansone re: EDIT -- totally understand, but since we have the ability to use blocks for custom methods as it stands, it seems reasonable that this could be merged in, then #49 could be updated to work with this new functionality as necessary (whether that means rolling this back or revising its implementation a bit).
I don't mean to imply that we should just ignore other PRs as these kinds of abstractions are discussed, but I don't think it should be a primary concern for this PR if it makes the most sense for this feature set (considering the other PR isn't merged in, and the focus of this PR is implementing this feature into the existing codebase). Hope that makes sense.
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.
@TrevorHinesley 👍 Totally agree, let's focus on the right implementation here and worry about #49 later. (It could be as simple as passing the serializer instance to
AttributeDefinition#serialize
and having it be called... lots of options here, not worth fretting about now though.)