From 159e7525fed5e570ad7f7000d66d9874692b5f1e Mon Sep 17 00:00:00 2001 From: Eloy Espinaco Date: Thu, 30 May 2019 12:20:45 -0300 Subject: [PATCH] Prevent normalization of polymorphic association Polymorphic associations have no klass names, so those should be not normalized. Fixes #588. Add tests using an action_storage like schema and add changelog entry. --- CHANGELOG.md | 3 +++ .../model_adapters/conditions_normalizer.rb | 6 ++++- .../conditions_normalizer_spec.rb | 25 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5bac240..c19c1206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* [#592](https://github.com/CanCanCommunity/cancancan/pull/592): Prevent normalization of through polymorphic associations.([@eloyesp][]) + ## 3.0.1 * [#583](https://github.com/CanCanCommunity/cancancan/pull/583): Fix regression when using a method reference block. ([@coorasse][]) @@ -643,3 +645,4 @@ Please read the [guide on migrating from CanCanCan 2.x to 3.0](https://github.co [@andrew-aladev]: https://github.com/andrew-aladev [@phaedryx]: https://github.com/phaedryx [@kaspernj]: https://github.com/kaspernj +[@eloyesp]: https://github.com/eloyesp diff --git a/lib/cancan/model_adapters/conditions_normalizer.rb b/lib/cancan/model_adapters/conditions_normalizer.rb index 46ceab71..e015d444 100644 --- a/lib/cancan/model_adapters/conditions_normalizer.rb +++ b/lib/cancan/model_adapters/conditions_normalizer.rb @@ -31,7 +31,7 @@ def calculate_result_hash(model_class, key, value) raise WrongAssociationName, "Association '#{key}' not defined in model '#{model_class.name}'" end - if reflection.options[:through].present? + if normalizable_association? reflection key = reflection.options[:through] value = { reflection.source_reflection_name => value } reflection = model_class.reflect_on_association(key) @@ -39,6 +39,10 @@ def calculate_result_hash(model_class, key, value) { key => normalize_conditions(reflection.klass.name.constantize, value) } end + + def normalizable_association?(reflection) + reflection.options[:through].present? && !reflection.options[:source_type].present? + end end end end diff --git a/spec/cancan/model_adapters/conditions_normalizer_spec.rb b/spec/cancan/model_adapters/conditions_normalizer_spec.rb index fdfb7f52..9368ae65 100644 --- a/spec/cancan/model_adapters/conditions_normalizer_spec.rb +++ b/spec/cancan/model_adapters/conditions_normalizer_spec.rb @@ -24,6 +24,14 @@ t.integer :user_id t.integer :article_id end + + create_table(:attachments) do |t| + t.references :record, polymorphic: true + t.integer :blob_id + end + + create_table(:blob) do |t| + end end class Article < ActiveRecord::Base @@ -31,6 +39,7 @@ class Article < ActiveRecord::Base has_many :comments, through: :spread_comments has_many :mentions has_many :mentioned_users, through: :mentions, source: :user + has_many :attachments, as: :record end class Comment < ActiveRecord::Base @@ -53,6 +62,16 @@ class User < ActiveRecord::Base has_many :mentions has_many :mentioned_articles, through: :mentions, source: :article end + + class Attachment < ActiveRecord::Base + belongs_to :record, polymorphic: true + belongs_to :blob + end + + class Blob < ActiveRecord::Base + has_many :attachments + has_many :articles, through: :attachments, source: :record, source_type: 'Article' + end end it 'simplifies has_many through associations' do @@ -61,6 +80,12 @@ class User < ActiveRecord::Base expect(rule.conditions).to eq(spread_comments: { article: { mentions: { user: { name: 'pippo' } } } }) end + it 'does not simplifies has_many through polymorphic associations' do + rule = CanCan::Rule.new(true, :read, Blob, articles: { id: 11 }) + CanCan::ModelAdapters::ConditionsNormalizer.normalize(Blob, [rule]) + expect(rule.conditions).to eq(articles: { id: 11 }) + end + it 'normalizes the has_one through associations' do class Supplier < ActiveRecord::Base has_one :accountant