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

type directive for serializer to control type field with json-api adapter #1213

Merged
merged 1 commit into from
Oct 2, 2015
Merged

type directive for serializer to control type field with json-api adapter #1213

merged 1 commit into from
Oct 2, 2015

Conversation

youroff
Copy link
Contributor

@youroff youroff commented Sep 29, 2015

This pull-requests implements type directive for serializer declaration. Which sets type attribute while using json-api adapter. So it's possible to use ProfileSerializer with User model and set type field to 'profile', like this:

class ProfileSerializer < ActiveModel::Serializer
  attributes :name
  type 'profile'
end

@NullVoxPopuli
Copy link
Contributor

First off, thanks for the PR!

My only concern is that type is often the name of a field used in single table inheritance for storing the class name of an object.

So, I guess that leaves two options:

  • change the name of the method from type to something else?
  • or write a test to simulate the potential problem (probably just rendering a model with a type field, and see if it still gets included in the resulting hash) (this would be my preference) If the test passes, you're good, and I'll give ya the 👍 :-)

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

There is a test which actually made me to change an approach. So now there's only class method test, which sets _test class variable. And this is used on the class level again, so it'll not interfer with type attribute.
Here's that test:
https://github.com/rails-api/active_model_serializers/blob/master/test/serializers/attribute_test.rb#L55

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

But I think it would be way smarter to have setting which class name to use (Serializer or Model) AND type directive to set it manually. If you like this idea, I'll add this feature.

@NullVoxPopuli
Copy link
Contributor

oh good! thanks for looking for that. :-)

you have my 👍

@beauby seems to be the JsonApi Adapter expert though, so I'll let him make the final call.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

I added functionality to derive resource type from serializer class, however it broke one test, which I'm not sure is really correct. Depends on standard which I'm not sure in. So the question is how we deal with namespaced models/serializers. Method underscore converts :: into /, however expected behavior is make it underscore as well. Opinions?

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

Hi @youroff, you are right, I added the possibility to override the type in a pending PR that got lost somewhere. I am totally up for this PR, I'll review it right away.

if ActiveModel::Serializer.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
unless serializer.class._type.nil?
serializer.class._type
else
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid unless with an else clause. Rewrite as an if with the positive clause first (https://github.com/bbatsov/ruby-style-guide#no-else-with-unless)

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

Done, but for namespace case we have to decide what to change: test or code. I'm not sure what json-api says about namespaced models.

else
serializer.object.class.model_name.plural
if ActiveModel::Serializer.config.type_source == :model
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be extracted to another PR. I'm generally not in favor of adding too many config options, and with the type method you introduced, there's virtually no use for this one, except for allowing wildly different workflows for users, which, as well, I'm not too keen on.

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

Thing is, JSON API explicitly does not say anything about namespaced models. There are PRs in the pipe for better handling of namespaced models, but my personal feeling is that the default should be to remove the namespace for the type attribute. We should probably open an RFC to discuss it though.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

I agree. So I remove namespace for this time to make tests pass?

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

Namespaces shouldn't be a problem here, are they?

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

They caused one test to fail. Last commit fixes it. If we agree to remove namespaces.

serializer.object.class.model_name.singular
if serializer.class._type.nil?
if ActiveModel::Serializer.config.type_source == :model
type = serializer.object.class.name.underscore
Copy link
Contributor

Choose a reason for hiding this comment

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

We shouldn't modify the behavior here (before it read the type from object.class.model_name (which is AR-specific, so we may change it later, but not now) to object.class.name).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem is that weird conversion of namespace comes from plural or singular methods. I Thought it would be reasonable to rely on general pluralization applied to string. But I can roll back to previous behavior of course.

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

What caused the test to fail was that you got the name from the object's class name instead of the AR model name.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

Right, but it doesn't really matter. Anyway we should decide either we leave namespace with separation of some form (/ or _) or we get rid of it.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

http://jsonapi.org/format/#document-member-names
At least it says that / is not allowed. But _ also doesn't make too much sense, because there is no way to tell namespace from just part of type.

serializer.object.class.model_name.singular
if serializer.class._type.nil?
if ActiveModel::Serializer.config.type_source == :model
type = serializer.object.class.name.demodulize.underscore
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather we stick with model_name, because it might very well be that there are 0 differences, but I have no certainty of that, and would rather change it in a subsequent PR if it makes sense. I get that it makes the pluralizing situation trickier, but it will be refactored soon anyways.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

So I roll everything back to type directive? I agree to get type from model_name, but why can't we leave type_source? With default setting (:model) it's transparent and type will override it anyways (if needed). I mean it's the feature that I would use in my project, so I'm really interested to keep it.

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

It's not that we can't leave type_source, it's just that PRs should be kept to one semantic change as much as possible, so that people can review them more easily, and the history remains clean.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

Btw, what plural and singular on ActiveModel::Name does is exactly the same as we did:
https://github.com/rails/rails/blob/0edb6465971f7d937fce2bf0a8e1e2b540d56e0a/activemodel/lib/active_model/naming.rb#L193-L195

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

Ok, so I'll just split this to two PR's?

@beauby
Copy link
Contributor

beauby commented Sep 29, 2015

That would be nice, yes.

@youroff
Copy link
Contributor Author

youroff commented Sep 29, 2015

Well, in general case it'll return ActiveModel::Name populated with class name of the model, but there are some edge cases, that I was not aware of (and I still don't understand the use-case). So probably we need tests for that weird case to make sure that model_name return exactly what we expect.

@youroff
Copy link
Contributor Author

youroff commented Oct 1, 2015

Made all corrections mentioned

@@ -37,6 +37,7 @@ class << self
attr_accessor :_cache_except
attr_accessor :_cache_options
attr_accessor :_cache_digest
attr_accessor :_type
Copy link
Member

Choose a reason for hiding this comment

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

I wish there were a better name for this, or a way to signal it is for json_api... resource_type_name ? no need to do anything

Copy link
Member

Choose a reason for hiding this comment

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

n/m, it can/should be removed since class_attribute :_type, instance_writer: false is added below

Copy link
Member

Choose a reason for hiding this comment

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

  • plz remove this accessor as the class_attribute below duplicates the behavior

@bf4
Copy link
Member

bf4 commented Oct 1, 2015

A few small things and this is ready to merge. 💯

@@ -122,6 +127,7 @@ def self.get_serializer_for(klass)
end

attr_accessor :object, :root, :meta, :meta_key, :scope
class_attribute :_type, instance_writer: false
Copy link
Member

Choose a reason for hiding this comment

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

  • this can go up near the other class methods

@bf4
Copy link
Member

bf4 commented Oct 2, 2015

Looks good, last thing to do is rebase it to squash it down to one commit. Lemme know if you want any tips on doing that..

@youroff
Copy link
Contributor Author

youroff commented Oct 2, 2015

If you have some short recipe how to do that, would be nice. Otherwise, I'll google. ;)

@youroff
Copy link
Contributor Author

youroff commented Oct 2, 2015

So what I did:

git checkout master
git pull
git checkout type_setting
git rebase master

As long as nothing changed since I started this PR, nothing happened... Should I merge to master locally or what?

@bf4
Copy link
Member

bf4 commented Oct 2, 2015

This is pretty good

  • http://help.exercism.io/git-workflow.html
  • A lot more awesome, but a bit more to learn http://rakeroutes.com/blog/deliberate-git/
  • What I would do is git rebase -i 305ec8dc50a16e462943cdffb4ebe346637c61a7^ turn all the pick into f, except the first, which I'd change to r and rewrite the commit message to Add Serializer 'type' directive to control type field, for use by the JsonApi adapter, then git fetch origin; git rebase origin/master; git push -f (if you use upstream, for rails-api/ams, then use that instead of origin)

@bf4
Copy link
Member

bf4 commented Oct 2, 2015

you missed updating your local master to the remote on origin :) see above for how I squash.. or if you want we can pair or I can do it.. up to you

@youroff
Copy link
Contributor Author

youroff commented Oct 2, 2015

Does it look ok? I expected previous commits to disappear, is that ok that they are still there?

@bf4
Copy link
Member

bf4 commented Oct 2, 2015

beautiful! GitHub still knows about the other commits... they're just not part of the PR. It git, you need to work hard to remove things :)

bf4 added a commit that referenced this pull request Oct 2, 2015
Add Serializer 'type' directive to control type field, for
 use by the JsonApi adapter
@bf4 bf4 merged commit a819da6 into rails-api:master Oct 2, 2015

def test_explicit_type_value
hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
assert_equal('profile', hash.fetch(:data).fetch(:type))
Copy link
Contributor

Choose a reason for hiding this comment

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

Why using fetch here instead of brackets?

Copy link
Member

Choose a reason for hiding this comment

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

Better error on failure

B mobile phone

On Oct 4, 2015, at 11:14 AM, Lucas Hosseini notifications@github.com wrote:

In test/adapter/json_api/resource_type_config_test.rb:

         end
       end
  •      def test_explicit_type_value
    
  •        hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
    
  •        assert_equal('profile', hash.fetch(:data).fetch(:type))
    
    Why using fetch here instead of brackets?


Reply to this email directly or view it on GitHub.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then why not use it there?

Copy link
Member

Choose a reason for hiding this comment

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

Not at computer now, could be oversight, not important in any case

B mobile phone

On Oct 4, 2015, at 12:33 PM, Lucas Hosseini notifications@github.com wrote:

In test/adapter/json_api/resource_type_config_test.rb:

         end
       end
  •      def test_explicit_type_value
    
  •        hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
    
  •        assert_equal('profile', hash.fetch(:data).fetch(:type))
    
    Then why not use it there?


Reply to this email directly or view it on GitHub.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed it's not important, but best to remain consistent.

Copy link
Member

Choose a reason for hiding this comment

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

remain consistent

please

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.

None yet

5 participants