familia 2.0.0.pre22 → 2.0.0.pre24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/claude-code-review.yml +8 -5
- data/CHANGELOG.rst +67 -0
- data/Gemfile.lock +8 -8
- data/docs/1106-participates_in-bidirectional-solution.md +201 -58
- data/examples/through_relationships.rb +275 -0
- data/lib/familia/features/relationships/README.md +1 -1
- data/lib/familia/features/relationships/participation/participant_methods.rb +59 -10
- data/lib/familia/features/relationships/participation/target_methods.rb +51 -7
- data/lib/familia/features/relationships/participation/through_model_operations.rb +150 -0
- data/lib/familia/features/relationships/participation.rb +39 -15
- data/lib/familia/features/relationships/participation_relationship.rb +19 -1
- data/lib/familia/features/relationships.rb +1 -1
- data/lib/familia/horreum/management.rb +36 -3
- data/lib/familia/version.rb +1 -1
- data/pr_agent.toml +6 -1
- data/try/edge_cases/find_by_dbkey_race_condition_try.rb +248 -0
- data/try/features/relationships/participation_commands_verification_spec.rb +1 -1
- data/try/features/relationships/participation_commands_verification_try.rb +1 -1
- data/try/features/relationships/participation_method_prefix_try.rb +133 -0
- data/try/features/relationships/participation_reverse_index_try.rb +1 -1
- data/try/features/relationships/{participation_bidirectional_try.rb → participation_reverse_methods_try.rb} +6 -6
- data/try/features/relationships/participation_through_try.rb +173 -0
- metadata +7 -2
|
@@ -30,7 +30,7 @@ RSpec.describe 'participation_commands_verification_try' do
|
|
|
30
30
|
field :display_domain
|
|
31
31
|
field :created_at
|
|
32
32
|
participates_in ReverseIndexCustomer, :domains, score: :created_at
|
|
33
|
-
participates_in ReverseIndexCustomer, :preferred_domains,
|
|
33
|
+
participates_in ReverseIndexCustomer, :preferred_domains, generate_participant_methods: true
|
|
34
34
|
class_participates_in :all_domains, score: :created_at
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -49,7 +49,7 @@ class ReverseIndexDomain < Familia::Horreum
|
|
|
49
49
|
field :created_at
|
|
50
50
|
|
|
51
51
|
participates_in ReverseIndexCustomer, :domains, score: :created_at
|
|
52
|
-
participates_in ReverseIndexCustomer, :preferred_domains,
|
|
52
|
+
participates_in ReverseIndexCustomer, :preferred_domains, generate_participant_methods: true
|
|
53
53
|
class_participates_in :all_domains, score: :created_at
|
|
54
54
|
end
|
|
55
55
|
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# try/features/relationships/participation_method_prefix_try.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require_relative '../../../lib/familia'
|
|
6
|
+
|
|
7
|
+
# Test the method_prefix: option for participates_in
|
|
8
|
+
# This allows shorter reverse method names for namespaced classes
|
|
9
|
+
|
|
10
|
+
# Simulate a namespaced target class
|
|
11
|
+
module ::Admin
|
|
12
|
+
class MethodPrefixTeam < Familia::Horreum
|
|
13
|
+
feature :relationships
|
|
14
|
+
|
|
15
|
+
identifier_field :team_id
|
|
16
|
+
field :team_id
|
|
17
|
+
field :name
|
|
18
|
+
|
|
19
|
+
sorted_set :members
|
|
20
|
+
sorted_set :admins
|
|
21
|
+
|
|
22
|
+
def init
|
|
23
|
+
@team_id ||= "team_#{SecureRandom.hex(4)}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Test class using method_prefix: option
|
|
29
|
+
class ::MethodPrefixUser < Familia::Horreum
|
|
30
|
+
feature :relationships
|
|
31
|
+
|
|
32
|
+
identifier_field :user_id
|
|
33
|
+
field :user_id
|
|
34
|
+
field :email
|
|
35
|
+
|
|
36
|
+
# Use method_prefix to get shorter method names
|
|
37
|
+
# Instead of admin_method_prefix_team_instances, we get team_instances
|
|
38
|
+
participates_in Admin::MethodPrefixTeam, :members, method_prefix: :team
|
|
39
|
+
|
|
40
|
+
def init
|
|
41
|
+
@user_id ||= "user_#{SecureRandom.hex(4)}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Test class using as: which should take precedence over method_prefix:
|
|
46
|
+
class ::MethodPrefixPriorityUser < Familia::Horreum
|
|
47
|
+
feature :relationships
|
|
48
|
+
|
|
49
|
+
identifier_field :user_id
|
|
50
|
+
field :user_id
|
|
51
|
+
field :email
|
|
52
|
+
|
|
53
|
+
# as: takes precedence over method_prefix:
|
|
54
|
+
participates_in Admin::MethodPrefixTeam, :admins, method_prefix: :team, as: :my_teams
|
|
55
|
+
|
|
56
|
+
def init
|
|
57
|
+
@user_id ||= "user_#{SecureRandom.hex(4)}"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Test class without method_prefix (default behavior)
|
|
62
|
+
class ::MethodPrefixDefaultUser < Familia::Horreum
|
|
63
|
+
feature :relationships
|
|
64
|
+
|
|
65
|
+
identifier_field :user_id
|
|
66
|
+
field :user_id
|
|
67
|
+
field :email
|
|
68
|
+
|
|
69
|
+
# Default: uses config_name (method_prefix_team - demodularized, no namespace)
|
|
70
|
+
participates_in Admin::MethodPrefixTeam, :members
|
|
71
|
+
|
|
72
|
+
def init
|
|
73
|
+
@user_id ||= "user_#{SecureRandom.hex(4)}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
@user = MethodPrefixUser.new(email: 'alice@example.com')
|
|
78
|
+
@priority_user = MethodPrefixPriorityUser.new(email: 'bob@example.com')
|
|
79
|
+
@default_user = MethodPrefixDefaultUser.new(email: 'charlie@example.com')
|
|
80
|
+
@team = Admin::MethodPrefixTeam.new(name: 'Engineering')
|
|
81
|
+
|
|
82
|
+
## method_prefix: generates shortened method names
|
|
83
|
+
# The method_prefix: :team option should generate team_* methods
|
|
84
|
+
@user.respond_to?(:team_instances)
|
|
85
|
+
#=> true
|
|
86
|
+
|
|
87
|
+
## method_prefix: generates team_ids method
|
|
88
|
+
@user.respond_to?(:team_ids)
|
|
89
|
+
#=> true
|
|
90
|
+
|
|
91
|
+
## method_prefix: generates team? method
|
|
92
|
+
@user.respond_to?(:team?)
|
|
93
|
+
#=> true
|
|
94
|
+
|
|
95
|
+
## method_prefix: generates team_count method
|
|
96
|
+
@user.respond_to?(:team_count)
|
|
97
|
+
#=> true
|
|
98
|
+
|
|
99
|
+
## method_prefix: does NOT generate verbose config_name methods
|
|
100
|
+
# The verbose admin_method_prefix_team_* methods should not be created
|
|
101
|
+
@user.respond_to?(:admin_method_prefix_team_instances)
|
|
102
|
+
#=> false
|
|
103
|
+
|
|
104
|
+
## as: takes precedence over method_prefix:
|
|
105
|
+
# When both as: and method_prefix: are provided, as: wins
|
|
106
|
+
@priority_user.respond_to?(:my_teams_instances)
|
|
107
|
+
#=> true
|
|
108
|
+
|
|
109
|
+
## as: takes precedence - method_prefix method NOT generated
|
|
110
|
+
@priority_user.respond_to?(:team_instances)
|
|
111
|
+
#=> false
|
|
112
|
+
|
|
113
|
+
## default behavior preserved when no method_prefix
|
|
114
|
+
# Without method_prefix:, the config_name is used (method_prefix_team)
|
|
115
|
+
# Note: config_name uses the class name without namespace
|
|
116
|
+
@default_user.respond_to?(:method_prefix_team_instances)
|
|
117
|
+
#=> true
|
|
118
|
+
|
|
119
|
+
## default behavior - no custom shortened method names
|
|
120
|
+
# The team_instances method is not generated unless method_prefix: :team is used
|
|
121
|
+
@default_user.respond_to?(:team_instances)
|
|
122
|
+
#=> false
|
|
123
|
+
|
|
124
|
+
## ParticipationRelationship stores method_prefix
|
|
125
|
+
# The relationship metadata should include the method_prefix
|
|
126
|
+
rel = MethodPrefixUser.participation_relationships.first
|
|
127
|
+
rel.method_prefix
|
|
128
|
+
#=> :team
|
|
129
|
+
|
|
130
|
+
## ParticipationRelationship method_prefix is nil for default
|
|
131
|
+
rel_default = MethodPrefixDefaultUser.participation_relationships.first
|
|
132
|
+
rel_default.method_prefix
|
|
133
|
+
#=> nil
|
|
@@ -28,7 +28,7 @@ class ReverseIndexDomain < Familia::Horreum
|
|
|
28
28
|
field :created_at
|
|
29
29
|
|
|
30
30
|
participates_in ReverseIndexCustomer, :domains, score: :created_at
|
|
31
|
-
participates_in ReverseIndexCustomer, :preferred_domains,
|
|
31
|
+
participates_in ReverseIndexCustomer, :preferred_domains, generate_participant_methods: true
|
|
32
32
|
class_participates_in :all_domains, score: :created_at
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# try/features/relationships/
|
|
1
|
+
# try/features/relationships/participation_reverse_methods_try.rb
|
|
2
2
|
#
|
|
3
3
|
# frozen_string_literal: true
|
|
4
4
|
|
|
5
5
|
require_relative '../../../lib/familia'
|
|
6
6
|
|
|
7
|
-
# Test demonstrating
|
|
7
|
+
# Test demonstrating reverse collection methods (generate_participant_methods: true)
|
|
8
8
|
# This shows the improvement from asymmetric to symmetric relationship access
|
|
9
9
|
|
|
10
10
|
# Setup test classes
|
|
@@ -51,8 +51,8 @@ class ::ProjectUser < Familia::Horreum
|
|
|
51
51
|
field :name
|
|
52
52
|
field :role
|
|
53
53
|
|
|
54
|
-
# Define
|
|
55
|
-
# These
|
|
54
|
+
# Define participation relationships with reverse collection methods
|
|
55
|
+
# These auto-generate methods like user.project_team_instances (when generate_participant_methods: true)
|
|
56
56
|
participates_in ProjectTeam, :members # Generates: user.project_team_instances
|
|
57
57
|
participates_in ProjectTeam, :admins # Also adds to user.project_team_instances (union)
|
|
58
58
|
participates_in ProjectOrganization, :employees # Generates: user.project_organization_instances
|
|
@@ -197,13 +197,13 @@ contracting_orgs_instances.map(&:name)
|
|
|
197
197
|
@team1.admins.to_a
|
|
198
198
|
#=> [@user1.identifier]
|
|
199
199
|
|
|
200
|
-
## Test
|
|
200
|
+
## Test symmetric consistency - forward direction
|
|
201
201
|
team1_member_ids = @team1.members.to_a
|
|
202
202
|
team1_members = ProjectUser.load_multi(team1_member_ids).compact
|
|
203
203
|
team1_members.map(&:name)
|
|
204
204
|
#=> ["Alice"]
|
|
205
205
|
|
|
206
|
-
## Test
|
|
206
|
+
## Test symmetric consistency - reverse direction
|
|
207
207
|
user1_teams = @user1.project_team_instances
|
|
208
208
|
user1_team_ids = user1_teams.map(&:identifier)
|
|
209
209
|
user1_team_ids.include?(@team1.identifier)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# try/features/relationships/participation_through_try.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
# Test through model support for participates_in relationships
|
|
6
|
+
|
|
7
|
+
require_relative '../../support/helpers/test_helpers'
|
|
8
|
+
|
|
9
|
+
# Define through model FIRST so it can be resolved
|
|
10
|
+
class ::ThroughTestMembership < Familia::Horreum
|
|
11
|
+
feature :object_identifier
|
|
12
|
+
feature :relationships
|
|
13
|
+
identifier_field :objid
|
|
14
|
+
field :through_test_customer_objid
|
|
15
|
+
field :through_test_domain_objid
|
|
16
|
+
field :role
|
|
17
|
+
field :updated_at
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class ::ThroughTestCustomer < Familia::Horreum
|
|
21
|
+
feature :object_identifier
|
|
22
|
+
feature :relationships
|
|
23
|
+
identifier_field :custid
|
|
24
|
+
field :custid
|
|
25
|
+
field :name
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ::ThroughTestDomain < Familia::Horreum
|
|
29
|
+
feature :object_identifier
|
|
30
|
+
feature :relationships
|
|
31
|
+
identifier_field :domain_id
|
|
32
|
+
field :domain_id
|
|
33
|
+
field :display_domain
|
|
34
|
+
field :created_at
|
|
35
|
+
participates_in ThroughTestCustomer, :domains, score: :created_at, through: :ThroughTestMembership
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Define backward compat classes in setup
|
|
39
|
+
class ::BackwardCompatCustomer < Familia::Horreum
|
|
40
|
+
feature :relationships
|
|
41
|
+
identifier_field :custid
|
|
42
|
+
field :custid
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class ::BackwardCompatDomain < Familia::Horreum
|
|
46
|
+
feature :relationships
|
|
47
|
+
identifier_field :domain_id
|
|
48
|
+
field :domain_id
|
|
49
|
+
field :created_at
|
|
50
|
+
participates_in BackwardCompatCustomer, :domains, score: :created_at
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Setup instance variables
|
|
54
|
+
@customer = ThroughTestCustomer.new(custid: 'cust_through_123', name: 'Through Test Customer')
|
|
55
|
+
@domain = ThroughTestDomain.new(domain_id: 'dom_through_456', display_domain: 'through-test.com', created_at: Familia.now.to_i)
|
|
56
|
+
@customer.save
|
|
57
|
+
@domain.save
|
|
58
|
+
|
|
59
|
+
@compat_customer = BackwardCompatCustomer.new(custid: 'compat_cust')
|
|
60
|
+
@compat_domain = BackwardCompatDomain.new(domain_id: 'compat_dom', created_at: Familia.now.to_i)
|
|
61
|
+
@compat_customer.save
|
|
62
|
+
@compat_domain.save
|
|
63
|
+
|
|
64
|
+
## ParticipationRelationship supports through parameter
|
|
65
|
+
Familia::Features::Relationships::ParticipationRelationship.members.include?(:through)
|
|
66
|
+
#=> true
|
|
67
|
+
|
|
68
|
+
## participates_in creates relationship with through parameter
|
|
69
|
+
@rel = ThroughTestDomain.participation_relationships.first
|
|
70
|
+
@rel.through
|
|
71
|
+
#=> :ThroughTestMembership
|
|
72
|
+
|
|
73
|
+
## Through class must have object_identifier feature
|
|
74
|
+
begin
|
|
75
|
+
class ::InvalidThroughModel < Familia::Horreum
|
|
76
|
+
feature :relationships
|
|
77
|
+
end
|
|
78
|
+
class ::BadDomain < Familia::Horreum
|
|
79
|
+
feature :relationships
|
|
80
|
+
field :name
|
|
81
|
+
participates_in ThroughTestCustomer, :bad_domains, through: :InvalidThroughModel
|
|
82
|
+
end
|
|
83
|
+
false
|
|
84
|
+
rescue ArgumentError => e
|
|
85
|
+
e.message.include?('must use `feature :object_identifier`')
|
|
86
|
+
end
|
|
87
|
+
#=> true
|
|
88
|
+
|
|
89
|
+
## Adding domain creates through model automatically
|
|
90
|
+
@membership1 = @customer.add_domains_instance(@domain)
|
|
91
|
+
@through_key = "through_test_customer:#{@customer.objid}:through_test_domain:#{@domain.objid}:through_test_membership"
|
|
92
|
+
@loaded_membership = ThroughTestMembership.load(@through_key)
|
|
93
|
+
@loaded_membership&.exists?
|
|
94
|
+
#=> true
|
|
95
|
+
|
|
96
|
+
## Through model receives through_attrs on add
|
|
97
|
+
@customer.remove_domains_instance(@domain)
|
|
98
|
+
@membership2 = @customer.add_domains_instance(@domain, through_attrs: { role: 'admin' })
|
|
99
|
+
@loaded_with_role = ThroughTestMembership.load(@through_key)
|
|
100
|
+
@loaded_with_role.role
|
|
101
|
+
#=> 'admin'
|
|
102
|
+
|
|
103
|
+
## add_domains_instance returns through model when using :through
|
|
104
|
+
@membership2.class.name
|
|
105
|
+
#=> "ThroughTestMembership"
|
|
106
|
+
|
|
107
|
+
## Returned through model can be chained
|
|
108
|
+
@membership2.respond_to?(:role)
|
|
109
|
+
#=> true
|
|
110
|
+
|
|
111
|
+
## Returned through model has role attribute set
|
|
112
|
+
@membership2.role
|
|
113
|
+
#=> 'admin'
|
|
114
|
+
|
|
115
|
+
## Removing domain destroys through model
|
|
116
|
+
@customer.remove_domains_instance(@domain)
|
|
117
|
+
@removed_check = ThroughTestMembership.load(@through_key)
|
|
118
|
+
@removed_check.nil? || !@removed_check.exists?
|
|
119
|
+
#=> true
|
|
120
|
+
|
|
121
|
+
## Adding twice updates existing, doesn't duplicate
|
|
122
|
+
@membership_v1 = @customer.add_domains_instance(@domain, through_attrs: { role: 'viewer' })
|
|
123
|
+
@check_v1 = ThroughTestMembership.load(@through_key)
|
|
124
|
+
@check_v1.role
|
|
125
|
+
#=> 'viewer'
|
|
126
|
+
|
|
127
|
+
## Second add updates the same through model
|
|
128
|
+
@membership_v2 = @customer.add_domains_instance(@domain, through_attrs: { role: 'editor' })
|
|
129
|
+
@check_v2 = ThroughTestMembership.load(@through_key)
|
|
130
|
+
@check_v2.role
|
|
131
|
+
#=> 'editor'
|
|
132
|
+
|
|
133
|
+
## Only one through model exists (same objid)
|
|
134
|
+
@check_v1.objid == @check_v2.objid
|
|
135
|
+
#=> true
|
|
136
|
+
|
|
137
|
+
## Models without :through work as before
|
|
138
|
+
@compat_result = @compat_customer.add_domains_instance(@compat_domain)
|
|
139
|
+
@compat_domain.in_backward_compat_customer_domains?(@compat_customer)
|
|
140
|
+
#=> true
|
|
141
|
+
|
|
142
|
+
## No through model created for backward compat
|
|
143
|
+
@compat_rel = BackwardCompatDomain.participation_relationships.first
|
|
144
|
+
@compat_rel.through.nil?
|
|
145
|
+
#=> true
|
|
146
|
+
|
|
147
|
+
## Backward compat returns self not through model
|
|
148
|
+
@compat_result.class.name
|
|
149
|
+
#=> "BackwardCompatCustomer"
|
|
150
|
+
|
|
151
|
+
## Through model sets updated_at on create
|
|
152
|
+
@customer.remove_domains_instance(@domain)
|
|
153
|
+
@membership_with_ts = @customer.add_domains_instance(@domain, through_attrs: { role: 'owner' })
|
|
154
|
+
@ts_check = ThroughTestMembership.load(@through_key)
|
|
155
|
+
@ts_check.updated_at.is_a?(Float)
|
|
156
|
+
#=> true
|
|
157
|
+
|
|
158
|
+
## updated_at is current
|
|
159
|
+
(Familia.now.to_f - @ts_check.updated_at) < 2.0
|
|
160
|
+
#=> true
|
|
161
|
+
|
|
162
|
+
## Through model updates updated_at on attribute change
|
|
163
|
+
@old_ts = @ts_check.updated_at
|
|
164
|
+
sleep 0.1
|
|
165
|
+
@membership_updated = @customer.add_domains_instance(@domain, through_attrs: { role: 'admin' })
|
|
166
|
+
@new_ts_check = ThroughTestMembership.load(@through_key)
|
|
167
|
+
@new_ts_check.updated_at > @old_ts
|
|
168
|
+
#=> true
|
|
169
|
+
|
|
170
|
+
# Cleanup
|
|
171
|
+
[@customer, @domain, @compat_customer, @compat_domain].each do |obj|
|
|
172
|
+
obj.destroy! if obj&.respond_to?(:destroy!) && obj.exists?
|
|
173
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: familia
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.0.
|
|
4
|
+
version: 2.0.0.pre24
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Delano Mandelbaum
|
|
@@ -218,6 +218,7 @@ files:
|
|
|
218
218
|
- examples/safe_dump.rb
|
|
219
219
|
- examples/sampling_demo.rb
|
|
220
220
|
- examples/single_connection_transaction_confusions.rb
|
|
221
|
+
- examples/through_relationships.rb
|
|
221
222
|
- familia.gemspec
|
|
222
223
|
- lib/familia.rb
|
|
223
224
|
- lib/familia/base.rb
|
|
@@ -275,6 +276,7 @@ files:
|
|
|
275
276
|
- lib/familia/features/relationships/participation/participant_methods.rb
|
|
276
277
|
- lib/familia/features/relationships/participation/rebuild_strategies.md
|
|
277
278
|
- lib/familia/features/relationships/participation/target_methods.rb
|
|
279
|
+
- lib/familia/features/relationships/participation/through_model_operations.rb
|
|
278
280
|
- lib/familia/features/relationships/participation_membership.rb
|
|
279
281
|
- lib/familia/features/relationships/participation_relationship.rb
|
|
280
282
|
- lib/familia/features/relationships/score_encoding.rb
|
|
@@ -315,6 +317,7 @@ files:
|
|
|
315
317
|
- pr_agent.toml
|
|
316
318
|
- pr_compliance_checklist.yaml
|
|
317
319
|
- try/edge_cases/empty_identifiers_try.rb
|
|
320
|
+
- try/edge_cases/find_by_dbkey_race_condition_try.rb
|
|
318
321
|
- try/edge_cases/hash_symbolization_try.rb
|
|
319
322
|
- try/edge_cases/json_serialization_try.rb
|
|
320
323
|
- try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb
|
|
@@ -361,12 +364,14 @@ files:
|
|
|
361
364
|
- try/features/relationships/indexing_commands_verification_try.rb
|
|
362
365
|
- try/features/relationships/indexing_rebuild_try.rb
|
|
363
366
|
- try/features/relationships/indexing_try.rb
|
|
364
|
-
- try/features/relationships/participation_bidirectional_try.rb
|
|
365
367
|
- try/features/relationships/participation_commands_verification_spec.rb
|
|
366
368
|
- try/features/relationships/participation_commands_verification_try.rb
|
|
369
|
+
- try/features/relationships/participation_method_prefix_try.rb
|
|
367
370
|
- try/features/relationships/participation_performance_improvements_try.rb
|
|
368
371
|
- try/features/relationships/participation_reverse_index_try.rb
|
|
372
|
+
- try/features/relationships/participation_reverse_methods_try.rb
|
|
369
373
|
- try/features/relationships/participation_target_class_resolution_try.rb
|
|
374
|
+
- try/features/relationships/participation_through_try.rb
|
|
370
375
|
- try/features/relationships/participation_unresolved_target_try.rb
|
|
371
376
|
- try/features/relationships/relationships_api_changes_try.rb
|
|
372
377
|
- try/features/relationships/relationships_edge_cases_try.rb
|