Skip to content

Commit f844206

Browse files
API / naming: special rules for actor-like models
A long forgotten feature to be ported from Rails Dynamic Associations. It was even mentioned in README as already implemented.
1 parent 908c78c commit f844206

10 files changed

Lines changed: 93 additions & 1 deletion

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ book.editors
7373
The list of models to be handled this way can be set with `actor_model_names` configuration parameter.
7474
It includes `User` by default.
7575

76+
``` ruby
77+
AdjustableSchema::Engine.configure do
78+
config.actor_model_names << 'Person'
79+
end
80+
```
81+
82+
> [!CAUTION]
83+
> Names are passed instead of model classes not to mess the loading up.
84+
7685
##### Self-referencing models
7786

7887
You may want to set up recursive relationships:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
module AdjustableSchema # :nodoc:
4+
concern :Actors do
5+
class_methods do
6+
def actor?
7+
Config.actor_models.any? { self <= it }
8+
end
9+
end
10+
end
11+
end

lib/adjustable_schema/active_record.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module ActiveRecord # :nodoc:
77
ActiveSupport.on_load :active_record do
88
include Associations
99
include Relationships
10+
include Actors
1011
end
1112
end
1213
end

lib/adjustable_schema/active_record/association/naming.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,20 @@ def name_without_role
3737
end
3838
end
3939

40+
module Actors # :nodoc:
41+
include Memery
42+
43+
memoize def name_with_role = {
44+
source: role.name,
45+
target: "#{role.name.passivize}_#{target_name}",
46+
}[direction]
47+
end
48+
4049
def initialize(...)
4150
super
4251

4352
extend Recursive if recursive?
53+
extend Actors if target.actor?
4454
end
4555

4656
memoize def name name = object_name

lib/adjustable_schema/config.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ def find_direction(...)
6666
module_function method
6767
end
6868

69+
memoize def actor_models
70+
Engine.config.actor_model_names
71+
.filter_map &:safe_constantize
72+
end
73+
6974
def association_names = Engine.config.names[:associations]
7075

7176
def normalize **options

lib/adjustable_schema/engine.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,9 @@ class Engine < ::Rails::Engine # :nodoc:
2020
},
2121
},
2222
}
23+
24+
config.actor_model_names = %w[
25+
User
26+
]
2327
end
2428
end

test/dummy/app/models/user.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# frozen_string_literal: true
2+
3+
class User < ApplicationRecord
4+
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class CreateUsers < ActiveRecord::Migration[8.0]
2+
def change
3+
create_table :users do |t|
4+
t.timestamps
5+
end
6+
end
7+
end

test/dummy/db/schema.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[7.1].define(version: 2023_12_24_105254) do
13+
ActiveRecord::Schema[8.0].define(version: 2025_04_23_093008) do
1414
create_table "adjustable_schema_relationship_roles", force: :cascade do |t|
1515
t.string "name"
1616
t.datetime "created_at", null: false
@@ -42,5 +42,10 @@
4242
t.datetime "updated_at", null: false
4343
end
4444

45+
create_table "users", force: :cascade do |t|
46+
t.datetime "created_at", null: false
47+
t.datetime "updated_at", null: false
48+
end
49+
4550
add_foreign_key "adjustable_schema_relationships", "adjustable_schema_relationship_roles", column: "role_id"
4651
end

test/lib/active_record/association/naming_test.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@
3737
_(target_association.name).must_equal :dummy_roled_model1s
3838
end
3939
end
40+
41+
describe 'when target acts as an actor' do
42+
let(:target) { User }
43+
44+
it 'names sources' do
45+
_(source_association.name).must_equal :dummy_roles
46+
end
47+
48+
it 'names targets' do
49+
_(target_association.name).must_equal :dummy_roled_users
50+
end
51+
end
4052
end
4153

4254
describe 'without a role' do
@@ -61,6 +73,18 @@
6173
_(target_association.name).must_equal :to_selves
6274
end
6375
end
76+
77+
describe 'when target acts as an actor' do
78+
let(:target) { User }
79+
80+
it 'names sources' do
81+
_(source_association.name).must_equal :users
82+
end
83+
84+
it 'names targets' do
85+
_(target_association.name).must_equal :users
86+
end
87+
end
6488
end
6589
end
6690

@@ -85,6 +109,18 @@
85109
_(target_association.relationships_name).must_equal :dummy_roled_model1_relationships
86110
end
87111
end
112+
113+
describe 'when target acts as an actor' do
114+
let(:target) { User }
115+
116+
it 'names sources' do
117+
_(source_association.relationships_name).must_equal :dummy_role_relationships
118+
end
119+
120+
it 'names targets' do
121+
_(target_association.relationships_name).must_equal :dummy_roled_user_relationships
122+
end
123+
end
88124
end
89125

90126
describe 'without a role' do

0 commit comments

Comments
 (0)