-
Notifications
You must be signed in to change notification settings - Fork 538
Continuation of #1217: Support creating polymorphic has-many relationships #1231
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
Continuation of #1217: Support creating polymorphic has-many relationships #1231
Conversation
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.
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.
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.
|
||
assert_jsonapi_response 400, msg: "Submitting a thing as a vehicle should raise a type mismatch error" | ||
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.
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.
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.
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]) |
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.
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.
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 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.
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.
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.
lib/jsonapi/resource.rb
Outdated
ids = relationship_key_values[:ids] | ||
|
||
related_records = relationship_resource_klass | ||
.records |
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.
@lgebhardt for supporting customizations, I think using records
is enough. Use find_by_keys
will also run includes for this query, which is unncessary.
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 missed this earlier: records
needs to be called as records(options)
@lgebhardt added tests for update, is there anything missing for merging? |
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.
@st0012 There are a few test failures masked by using assert
instead of assert_equal
.
lib/jsonapi/resource.rb
Outdated
ids = relationship_key_values[:ids] | ||
|
||
related_records = relationship_resource_klass | ||
.records |
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 missed this earlier: records
needs to be called as records(options)
lib/jsonapi/resource.rb
Outdated
.records | ||
.where({relationship_resource_klass._primary_key => ids}) | ||
|
||
missed_ids = ids - related_records.map(&:id) |
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.
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)
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.
👍
person = Person.find(body.dig("data", "id")) | ||
|
||
assert "Reo", person.name | ||
assert 2, person.vehicles.count |
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.
These asserts should be assert_equal
. Once fixed this test is failing with only the last vehicle type being created.
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.
ah sorry 😅
a0ec607
to
2081af6
Compare
@lgebhardt all updated! |
@st0012 Thanks for working on this. I squashed your changes and pushed them to release-0-9 |
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:
New Feature Submissions:
Bug fixes and Changes to Core Features:
Test Plan:
Reviewer Checklist: