diff --git a/.all-contributorsrc b/.all-contributorsrc
index be487590..156c6814 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -104,6 +104,17 @@
"code",
"test"
]
+ },
+ {
+ "login": "jpalumickas",
+ "name": "Justas Palumickas",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/2738630?v=3",
+ "profile": "https://jpalumickas.com",
+ "contributions": [
+ "bug",
+ "code",
+ "test"
+ ]
}
]
}
diff --git a/README.md b/README.md
index 844e44d6..597f8f5c 100644
--- a/README.md
+++ b/README.md
@@ -179,7 +179,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
| [
Vesa Laakso](http://vesalaakso.com)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) [π](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) π [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) [π](https://github.com/Venuu/jsonapi-authorization/issues?q=author%3Avalscion) π¬ π | [
Emil SΓ₯gfors](https://github.com/lime)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) [π](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) π [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) [π](https://github.com/Venuu/jsonapi-authorization/issues?q=author%3Alime) π¬ π | [
Matthias Grundmann](https://github.com/matthias-g)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) [π](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) π¬ | [
Thibaud Guillaume-Gentil](http://thibaud.gg)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=thibaudgg) | [
Daniel SchweighΓΆfer](http://netsteward.net)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=acid) | [
Bruno Sofiato](https://github.com/bsofiato)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=bsofiato) | [
Adam Robertson](https://github.com/arcreative)
[π](https://github.com/Venuu/jsonapi-authorization/commits?author=arcreative) |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
-| [
Greg Fisher](https://github.com/gnfisher)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) | [
Sam](http://samlh.com)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) |
+| [
Greg Fisher](https://github.com/gnfisher)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) | [
Sam](http://samlh.com)
[π»](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) | [
Justas Palumickas](https://jpalumickas.com)
[π](https://github.com/Venuu/jsonapi-authorization/issues?q=author%3Ajpalumickas) [π»](https://github.com/Venuu/jsonapi-authorization/commits?author=jpalumickas) [β οΈ](https://github.com/Venuu/jsonapi-authorization/commits?author=jpalumickas) |
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
\ No newline at end of file
diff --git a/lib/jsonapi/authorization/authorizing_processor.rb b/lib/jsonapi/authorization/authorizing_processor.rb
index 0856ea20..ae1137d0 100644
--- a/lib/jsonapi/authorization/authorizing_processor.rb
+++ b/lib/jsonapi/authorization/authorizing_processor.rb
@@ -269,6 +269,8 @@ def related_models_with_context
data[rel_type].flat_map do |assoc_name, assoc_value|
related_models =
case assoc_value
+ when nil
+ nil
when Hash # polymorphic relationship
resource_class = @resource_klass.resource_for(assoc_value[:type].to_s)
resource_class.find_by_key(assoc_value[:id], context: context)._model
diff --git a/lib/jsonapi/authorization/default_pundit_authorizer.rb b/lib/jsonapi/authorization/default_pundit_authorizer.rb
index 0f197b7e..a1974189 100644
--- a/lib/jsonapi/authorization/default_pundit_authorizer.rb
+++ b/lib/jsonapi/authorization/default_pundit_authorizer.rb
@@ -260,7 +260,11 @@ def authorize_related_records(source_record, related_records_with_context)
when :to_many
replace_to_many_relationship(source_record, records, relation_name)
when :to_one
- replace_to_one_relationship(source_record, records, relation_name)
+ if records.nil?
+ remove_to_one_relationship(source_record, relation_name)
+ else
+ replace_to_one_relationship(source_record, records, relation_name)
+ end
end
end
end
diff --git a/spec/jsonapi/authorization/default_pundit_authorizer_spec.rb b/spec/jsonapi/authorization/default_pundit_authorizer_spec.rb
index 0b0b04a7..f0e9a63d 100644
--- a/spec/jsonapi/authorization/default_pundit_authorizer_spec.rb
+++ b/spec/jsonapi/authorization/default_pundit_authorizer_spec.rb
@@ -207,6 +207,52 @@
end
end
+ describe 'with "relation_type: :to_one" and records is nil' do
+ let(:related_records_with_context) do
+ [{
+ relation_name: :author,
+ relation_type: :to_one,
+ records: nil
+ }]
+ end
+
+ subject(:method_call) do
+ -> { authorizer.replace_fields(source_record, related_records_with_context) }
+ end
+
+ context 'authorized for remove_? and authorized for update? on source record' do
+ before { stub_policy_actions(source_record, remove_author?: true, update?: true) }
+ it { is_expected.not_to raise_error }
+ end
+
+ context 'unauthorized for remove_? and authorized for update? on source record' do
+ before { stub_policy_actions(source_record, remove_author?: false, update?: true) }
+ it { is_expected.to raise_error(::Pundit::NotAuthorizedError) }
+ end
+
+ context 'authorized for remove_? and unauthorized for update? on source record' do
+ before { stub_policy_actions(source_record, remove_author?: true, update?: false) }
+ it { is_expected.to raise_error(::Pundit::NotAuthorizedError) }
+ end
+
+ context 'unauthorized for remove_? and unauthorized for update? on source record' do
+ before { stub_policy_actions(source_record, remove_author?: false, update?: false) }
+ it { is_expected.to raise_error(::Pundit::NotAuthorizedError) }
+ end
+
+ context 'where remove_? is undefined' do
+ context 'authorized for update? on source record' do
+ before { stub_policy_actions(source_record, update?: true) }
+ it { is_expected.not_to raise_error }
+ end
+
+ context 'unauthorized for update? on source record' do
+ before { stub_policy_actions(source_record, update?: false) }
+ it { is_expected.to raise_error(::Pundit::NotAuthorizedError) }
+ end
+ end
+ end
+
describe 'with "relation_type: :to_many"' do
let(:related_records) { Array.new(3) { Comment.new } }
let(:related_records_with_context) do
diff --git a/spec/requests/tricky_operations_spec.rb b/spec/requests/tricky_operations_spec.rb
index 1eaf156a..9cfb4a56 100644
--- a/spec/requests/tricky_operations_spec.rb
+++ b/spec/requests/tricky_operations_spec.rb
@@ -168,4 +168,31 @@
it { is_expected.to be_forbidden }
end
end
+
+ describe 'PATCH /articles/:id (nullifying to-one relationship)' do
+ let(:article) { articles(:article_with_author) }
+ let(:json) do
+ <<-EOS.strip_heredoc
+ {
+ "data": {
+ "id": "#{article.external_id}",
+ "type": "articles",
+ "relationships": { "author": null }
+ }
+ }
+ EOS
+ end
+ let(:policy_scope) { Article.all }
+ subject(:last_response) { patch("/articles/#{article.external_id}", json) }
+
+ before do
+ allow_operation(
+ 'replace_fields',
+ article,
+ [{ relation_type: :to_one, relation_name: :author, records: nil }]
+ )
+ end
+
+ it { is_expected.to be_successful }
+ end
end