Skip to content

Commit

Permalink
Merge pull request #30 from kaspth/polymorphic-associated-objects-via…
Browse files Browse the repository at this point in the history
…-modules

Feels a bit iffy, but it's easier for us to support versus trying to bake in "polymorphic" support via inheritance.

See #25 and #29 for the previous discussion.

So given the tradeoffs I think this is the best we've got.
  • Loading branch information
kaspth authored Dec 10, 2024
2 parents f9204ca + 5470ef5 commit 1299308
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,68 @@ class Post::PublisherTest < ActiveSupport::TestCase
end
```
### Polymorphic Associated Objects
If you want to share logic between associated objects, you can do so via standard Ruby modules:
```ruby
# app/models/pricing.rb
module Pricing
# If you need to share an `extension` across associated objects you can override `Module::included` like this:
def self.included(object) = object.extension do
# Add common integration methods onto `Account`/`User` when the module is included.
# See the `extension` block in the `Extending` section above for an example.
end

def price_set?
# Instead of referring to `account` or `user`, use the `record` method to target either.
record.price_cents.positive?
end
end

# app/models/account/pricing.rb
class Account::Pricing < ActiveRecord::AssociatedObject
include ::Pricing
end

# app/models/user/pricing.rb
class User::Pricing < ActiveRecord::AssociatedObject
include ::Pricing
end
```
Now we can call `account.pricing.price_set?` & `user.pricing.price_set?`.
> [!NOTE]
> Polymorphic Associated Objects are definitely a more advanced topic,
> so you need to know your Ruby module hierarchy and how to track what `self` changes to fairly well.
#### Using `ActiveSupport::Concern` as an alternative
If you prefer the look of Active Support concerns, here's the equivalent to the above Ruby module:
```ruby
# app/models/pricing.rb
module Pricing
extend ActiveSupport::Concern

included do
extension do
# Add common integration methods onto `Account`/`User` when the concern is included.
end
end

def price_set?
# Instead of referring to `account` or `user`, use the `record` method to target either.
record.price_cents.positive?
end
end
```
Active Support concerns have some extra features that standard Ruby modules don't, like support for deeply-nested concerns and `class_methods do`.
In this case, if you're reaching for those, you're probably building something too intricate and potentially brittle.
### Active Job integration via GlobalID
Associated Objects include `GlobalID::Identification` and have automatic Active Job serialization support that looks like this:
Expand Down

0 comments on commit 1299308

Please sign in to comment.