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 relationship ID to be overwritten for belongs_to relationships #2128

Closed
wants to merge 1 commit into from
Closed

Allow relationship ID to be overwritten for belongs_to relationships #2128

wants to merge 1 commit into from

Conversation

greysteil
Copy link
Contributor

@greysteil greysteil commented May 9, 2017

Purpose

If the id attribute for a class isn't taken directly from the object when serializing it, it may be desirable for other classes that serialize a relationship with that class to overwrite the relationship IDs they serialize.

For example, suppose we have:

class Repo < Model
  attributes :id, :github_id, :name
  associations :configs
end

class Config < Model
  attributes :id
  belongs_to :repo
end

class RepoSerializer < ActiveModel::Serializer
  attributes :id, :name

  has_many :update_configs

  def id
    object.github_id
  end
end

class ConfigSerializer < ActiveModel::Serializer
  attributes :id
  belongs_to :repo
end

In the above example, serializing a list of Repos will give the github_id for each one, but serializing a Config will give the id for its parent repo.

Changes

I've updated the belongs_to? path of Relationship#data_for_one to use read_attribute_for_serialization instead of object.send to fetch the serialized foreign key. This allows the serialized relationship ID to be
overwritten using:

class ConfigSerializer < ActiveModel::Serializer
  ...

  def repo_id
    object.repo.github_id
  end
end

Caveats

Ideally AMS would inspect the RepoSerializer when serializing the Config, and realise it can't just output the foreign key. Unfortunately, getting the serialization class for the child repo currently requires loading the record (via evaluating lazy_assocation), and loses the performance benefit of the existing belongs_to? path.

Related GitHub issues

#2125. (Not resolved by this, but the ID issue is at least improved, for no performance cost.)

Additional helpful information

@greysteil
Copy link
Contributor Author

@bf4 - hadn't see #2125 when I put this together and didn't realise this behaviour was considered a bug. I can change approach if you'd rather?

@@ -146,6 +146,9 @@ class CustomBlogSerializer < ActiveModel::Serializer
attribute :special_attribute
has_many :articles
end
class ExternalBlog < Blog
attributes :external_id
end
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 in the test/serializers/associations_test.rb. (This file is big enough :) )

@bf4
Copy link
Member

bf4 commented May 11, 2017

This looks fine to me. I don't mind hiding the object behind the serializer a little more :)

Just the one change

If the `id` attribute for a class isn't taken directly from the object when
serializing it, it may be desirible for other classes that serialize a
relationship with that class to overwrite the relationship IDs they serialize.

For example, suppose we have:

```(ruby)
class Repo < Model
  attributes :id, :github_id, :name
  associations :configs
end

class Config < Model
  attributes :id
  belongs_to :repo
end

class RepoSerializer < ActiveModel::Serializer
  attributes :id, :name

  has_many :update_configs

  def id
    object.github_id
  end
end

class ConfigSerializer < ActiveModel::Serializer
  attributes :id
  belongs_to :repo
end
```

In the above example, serializing a list of `Repo`s will give the `github_id`
for each one, but serializing a `Config` will give the `id` for its parent repo.

Ideally AMS would inspect the `RepoSerializer` when serializing the `Config`,
and realise it can't just output the foreign key. Unfortunately, getting the
serialization class for the child repo currently requires loading the record
(via evaluating `lazy_assocation`), and loses the performance benefit of the
existing `belongs_to?` path. Instead, I've opted to use
`read_attribute_for_serialization` instead of `object.send` to fetch the
serialized foreign key. This allows the serialized relationship ID to be
overwritten using

```(ruby)
class ConfigSerializer < ActiveModel::Serializer
  ...

  def repo_id
    object.repo.github_id
  end
end
```
@bf4
Copy link
Member

bf4 commented May 12, 2017

Would mind closing this PR and opening a new one against 0-10-stable? per #2121

@greysteil greysteil closed this May 12, 2017
@greysteil greysteil deleted the allow-id-overwriting branch May 12, 2017 14:23
@greysteil
Copy link
Contributor Author

Done. #2130.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants