Skip to content

Continuation of #1217: Support creating polymorphic has-many relationships#1231

Closed
st0012 wants to merge 9 commits intoJSONAPI-Resources:release-0-9from
st0012:fix_creating_polymorphic_has_many_relations
Closed

Continuation of #1217: Support creating polymorphic has-many relationships#1231
st0012 wants to merge 9 commits intoJSONAPI-Resources:release-0-9from
st0012:fix_creating_polymorphic_has_many_relations

Conversation

@st0012
Copy link
Copy Markdown
Contributor

@st0012 st0012 commented Mar 15, 2019

This is a continuation of #1217, which fixes its failing tests (thanks for @saravanak's hard work!).

The cause of #1217's failure is data mutation between test cases: the integration test's post request creates a new record, and it fails other tests (under certain execution order). So my additional commit is to keep the database clean (with database_cleaner before/after each integration test suite.

All Submissions:

  • I've checked to ensure there aren't other open Pull Requests for the same update/change.
  • I've submitted a ticket for my issue if one did not already exist.
  • My submission passes all tests. (Please run the full test suite locally to cut down on noise from travis failures.)
  • I've used Github auto-closing keywords in the commit message or the description.
  • I've added/updated tests for this change.

New Feature Submissions:

  • I've submitted an issue that describes this feature, and received the go ahead from the maintainers.
  • My submission includes new tests.
  • My submission maintains compliance with JSON:API.

Bug fixes and Changes to Core Features:

  • I've included an explanation of what the changes do and why I'd like you to include them.
  • I've provided test(s) that fails without the change.

Test Plan:

Reviewer Checklist:

  • Maintains compliance with JSON:API
  • Adequate test coverage exists to prevent regressions

saravanak and others added 2 commits January 28, 2019 13:18
If we create/modify/delete records (via requests) in integration tests,
it might affect other tests' test result. The ideal way is to keep
integration test data isolated. And by adding database_cleaner, we can
make sure database is reset between each test cases.
@st0012 st0012 changed the title Fix creating polymorphic has many relations Continuation of #1217: Support creating polymorphic has-many relationships Mar 15, 2019
Copy link
Copy Markdown
Contributor

@lgebhardt lgebhardt left a comment

Choose a reason for hiding this comment

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

Thanks @saravanak and @st0012 This is a good start, but it's not thoroughly tested and further work is needed downstream in the Resource for creating the relationship links.

Comment thread lib/jsonapi/request_parser.rb Outdated

assert_jsonapi_response 400, msg: "Submitting a thing as a vehicle should raise a type mismatch error"
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's test cases where multiple vehicles are provided. Tests should include mismatches of types, such as

'relationships' => {
             'vehicles' => {'data' => [{'type' => 'car', 'id' => '1'}, {'type' => 'car', 'id' => '2'}]}, #vehicle 2 is actually a boat
           }

Test should probably be repeated for updates, though as of now they should go through the same path.

Comment thread test/integration/requests/request_test.rb
st0012 added 3 commits March 18, 2019 15:00
We do this in following steps

1) Get the sub-resource's model class with `Resource.model_hint`'s info
2) Query the records with subclass instead of polymorphic class
3) Return 404 if we get any record not found error

The reason to raise RecordNotFound instead of TypeMismatch is that
type mismatch means requires 2 conditions:
  - the id can't be used to find any record in current subclass (Car)
  - but in the meantime, it does exists for the superclass (Vehicle)
And this means we need to perform additional query to prove the second
condition, which is kind of a waste.
Comment thread lib/jsonapi/resource.rb Outdated
Comment thread lib/jsonapi/resource.rb Outdated
begin
related_records = relationship_klass.find(relationship_key_values[:ids])
rescue ActiveRecord::RecordNotFound
fail JSONAPI::Exceptions::RecordNotFound.new(relationship_key_values[:ids])
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason to raise RecordNotFound instead of TypeMismatch is that type mismatch requires 2 conditions:
- the id can't be used to find any record in current subclass (Car)
- but in the meantime, it does exists for the superclass (Vehicle)
And this means we need to perform additional query to prove the second condition, which is kind of a waste.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I tend to agree it's kind of a waste, but from a JSON API perspective it's not known that the backing table is sharing a common set of IDs. So there really isn't a Car with id 2 so the system should raise an error.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's use find_by_keys, like https://github.com/cerebris/jsonapi-resources/blob/master/lib/jsonapi/resource.rb#L251. That way any overrides will get applied. This might be the case if people are doing permission checking for these related resources.

We need to use Resource.records as our query base to invoke user
customizations. And because the ivar inheritance, we need to manually
call model_name on subclasses to make this work.
Comment thread lib/jsonapi/resource.rb Outdated
ids = relationship_key_values[:ids]

related_records = relationship_resource_klass
.records
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@lgebhardt for supporting customizations, I think using records is enough. Use find_by_keys will also run includes for this query, which is unncessary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I missed this earlier: records needs to be called as records(options)

@st0012
Copy link
Copy Markdown
Contributor Author

st0012 commented Mar 19, 2019

@lgebhardt added tests for update, is there anything missing for merging?

Copy link
Copy Markdown
Contributor

@lgebhardt lgebhardt left a comment

Choose a reason for hiding this comment

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

@st0012 There are a few test failures masked by using assert instead of assert_equal.

Comment thread lib/jsonapi/resource.rb Outdated
ids = relationship_key_values[:ids]

related_records = relationship_resource_klass
.records
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I missed this earlier: records needs to be called as records(options)

Comment thread lib/jsonapi/resource.rb Outdated
.records
.where({relationship_resource_klass._primary_key => ids})

missed_ids = ids - related_records.map(&:id)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We need to account for alternate primary keys, and I think we can skip creating the models so pluck will save a few cycles.

missed_ids = ids - related_records.pluck(relationship_resource_klass._primary_key)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

👍

person = Person.find(body.dig("data", "id"))

assert "Reo", person.name
assert 2, person.vehicles.count
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These asserts should be assert_equal. Once fixed this test is failing with only the last vehicle type being created.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ah sorry 😅

@st0012 st0012 force-pushed the fix_creating_polymorphic_has_many_relations branch from a0ec607 to 2081af6 Compare March 19, 2019 15:26
@st0012
Copy link
Copy Markdown
Contributor Author

st0012 commented Mar 19, 2019

@lgebhardt all updated!

lgebhardt pushed a commit that referenced this pull request Mar 19, 2019
@lgebhardt
Copy link
Copy Markdown
Contributor

@st0012 Thanks for working on this. I squashed your changes and pushed them to release-0-9

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.

3 participants