Skip to content

Fix creating polymorphic associations #35

Merged
Drew-Goddyn merged 3 commits intoclio:masterfrom
Drew-Goddyn:fix-creating-polymorhic-records
Nov 18, 2020
Merged

Fix creating polymorphic associations #35
Drew-Goddyn merged 3 commits intoclio:masterfrom
Drew-Goddyn:fix-creating-polymorhic-records

Conversation

@Drew-Goddyn
Copy link
Copy Markdown
Contributor

@Drew-Goddyn Drew-Goddyn commented Nov 6, 2020

We previously were only including the BelongsToPolymorphicAssociation module in specific activerecord versions. This module overides the replace_keys method to ensure we aren't sending the class's #polymorphic_name when creating associations. When this isn't included we send the polymorphic name which includes the class's namespace and can cause us to not find it in the mapping (assuming the mappings don't include namespaces).

By including it, we send the class object itself and let our fallback logic kick in to try several methods until we get a hit from the mapping.

It also cleans up a few other gotchas like creating a new ModuleGenerator. The generator defines an anonmyous module we can use for calling super since the previous implementation was all inline causing us to capture local variables in the blocks and behave oddly.

require "polymorphic_integer_type/extensions"
require "polymorphic_integer_type/mapping"
require "polymorphic_integer_type/module_generator"
require "polymorphic_integer_type/belongs_to_polymorphic_association_extension"
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.

this require was the heart of the issue, as it was previously tied to an active record version < 5.2.0, but in reality we want it all the time

private def replace_keys(record)
super
owner[reflection.foreign_type] = record.class.base_class
owner[reflection.foreign_type] = record.class
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.

send the class object instead of the base_class so we can try several methods like #polymorphic_name, #sti_name, #to_s etc

end

include(foreign_type_extension)
ModuleGenerator.generate_and_include(self, foreign_type, name)
Copy link
Copy Markdown
Contributor Author

@Drew-Goddyn Drew-Goddyn Nov 6, 2020

Choose a reason for hiding this comment

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

previously, the define_method blocks that were abstracted would capture the mapping variable and could cause really odd behaviour when stubbing it in specs, this ensures that all the stuff it needs is encapsulated in a class and isn't affected by the outside world.

@@mapping[as] || {}
end

singleton_class.send(:alias_method, :[]=, :add)
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.

thought it was odd we have an #add method that behaves canonically like []= so made an alias 🤷‍♂️

spec.add_development_dependency "rspec"
spec.add_development_dependency "sqlite3"
spec.add_development_dependency "byebug"
spec.add_development_dependency "pry-byebug"
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.

cause we want choice! (I hate debugger since it has no colors)

Comment thread spec/support/link.rb
belongs_to :source, polymorphic: true, integer_type: true
belongs_to :target, polymorphic: true, integer_type: true

def source=(val)
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.

these appeared unused and didn't affect specs so bye bye

@Drew-Goddyn Drew-Goddyn requested review from a team, doliveirakn and fimmtiu and removed request for a team November 6, 2020 20:42
@Drew-Goddyn Drew-Goddyn changed the title Fix creating polymorhic records Fix creating polymorphic associations Nov 6, 2020
@Drew-Goddyn Drew-Goddyn requested review from daniel-almeida and kamillus and removed request for doliveirakn November 6, 2020 20:55
@@ -0,0 +1,34 @@
module PolymorphicIntegerType
class ModuleGenerator
def self.generate_and_include(klass,foreign_type, name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Do you have a unit test for this method?

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.

It's pretty difficult to unit test this in isolation since it involves setting up polymorphic models and then overriding some of the behaviour(which is basically what we do in the specs already). This functionality was already tested thoroughly in the specs and this just abstracts it away into class


# Required way to dynamically define a class method on the model
singleton_class.__send__(:define_method, "#{foreign_type}_mapping") do
define_singleton_method("#{foreign_type}_mapping") do
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.

just switching to more idiomatic way of defining singleton methods

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.

IIRC, define_singleton_method didn't exist in earlier versions of Ruby when we first wrote this module, and __send__ was the only way to do it. This is much nicer to read.

Comment thread spec/polymorphic_integer_type_spec.rb Outdated

link = Namespaced::Plant.create(name: "Oak").source_links.new
expect(link.source_type).to eq("Namespaced::Plant")
allow(Link).to receive(:source_type_mapping).and_return({1 => "Person", 2 => "Animal", 3 => "Plant"})
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.

woops, don't think this is needed, gonna remove it

Copy link
Copy Markdown

@daniel-almeida daniel-almeida left a comment

Choose a reason for hiding this comment

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

Good job with the comments! They made this much easier to review. 💯

@Drew-Goddyn Drew-Goddyn requested a review from kamillus November 17, 2020 21:25
Comment thread spec/support/namespaced_activity.rb Outdated
@@ -0,0 +1,11 @@
module Namespaced
class Activity< ActiveRecord::Base
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.

Suggested change
class Activity< ActiveRecord::Base
class Activity < ActiveRecord::Base

Copy link
Copy Markdown
Contributor

@fimmtiu fimmtiu left a comment

Choose a reason for hiding this comment

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

Approved with one trivial suggestion.

@Drew-Goddyn Drew-Goddyn force-pushed the fix-creating-polymorhic-records branch from bb77ff5 to 9b62446 Compare November 18, 2020 20:37
@Drew-Goddyn Drew-Goddyn merged commit 2ca2095 into clio:master Nov 18, 2020
@Drew-Goddyn Drew-Goddyn deleted the fix-creating-polymorhic-records branch November 18, 2020 20:38
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.

4 participants