acts_as_list 1.2.1 → 1.2.3

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.
@@ -1,177 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Shared
4
- module ArrayScopeList
5
- def setup
6
- (1..4).each { |counter| ArrayScopeListMixin.create! pos: counter, parent_id: 5, parent_type: 'ParentClass' }
7
- (1..4).each { |counter| ArrayScopeListMixin.create! pos: counter, parent_id: 6, parent_type: 'ParentClass' }
8
- end
9
-
10
- def test_reordering
11
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
12
-
13
- ArrayScopeListMixin.where(id: 2).first.move_lower
14
- assert_equal [1, 3, 2, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
15
-
16
- ArrayScopeListMixin.where(id: 2).first.move_higher
17
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
18
-
19
- ArrayScopeListMixin.where(id: 1).first.move_to_bottom
20
- assert_equal [2, 3, 4, 1], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
21
-
22
- ArrayScopeListMixin.where(id: 1).first.move_to_top
23
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
24
-
25
- ArrayScopeListMixin.where(id: 2).first.move_to_bottom
26
- assert_equal [1, 3, 4, 2], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
27
-
28
- ArrayScopeListMixin.where(id: 4).first.move_to_top
29
- assert_equal [4, 1, 3, 2], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
30
-
31
- ArrayScopeListMixin.where(id: 4).first.insert_at(4)
32
- assert_equal [1, 3, 2, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
33
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:pos)
34
- end
35
-
36
- def test_move_to_bottom_with_next_to_last_item
37
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
38
- ArrayScopeListMixin.where(id: 3).first.move_to_bottom
39
- assert_equal [1, 2, 4, 3], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
40
- end
41
-
42
- def test_next_prev
43
- assert_equal ArrayScopeListMixin.where(id: 2).first, ArrayScopeListMixin.where(id: 1).first.lower_item
44
- assert_nil ArrayScopeListMixin.where(id: 1).first.higher_item
45
- assert_equal ArrayScopeListMixin.where(id: 3).first, ArrayScopeListMixin.where(id: 4).first.higher_item
46
- assert_nil ArrayScopeListMixin.where(id: 4).first.lower_item
47
- end
48
-
49
- def test_injection
50
- item = ArrayScopeListMixin.new(parent_id: 1, parent_type: 'ParentClass')
51
- assert_equal "pos", item.position_column
52
- end
53
-
54
- def test_insert
55
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
56
- assert_equal 1, new.pos
57
- assert new.first?
58
- assert new.last?
59
-
60
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
61
- assert_equal 2, new.pos
62
- assert !new.first?
63
- assert new.last?
64
-
65
- new = ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass') }
66
- assert_equal_or_nil $default_position,new.pos
67
- assert_equal $default_position.is_a?(Integer), new.first?
68
- assert !new.last?
69
-
70
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
71
- assert_equal 3, new.pos
72
- assert !new.first?
73
- assert new.last?
74
-
75
- new = ArrayScopeListMixin.create(parent_id: 0, parent_type: 'ParentClass')
76
- assert_equal 1, new.pos
77
- assert new.first?
78
- assert new.last?
79
- end
80
-
81
- def test_insert_at
82
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
83
- assert_equal 1, new.pos
84
-
85
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
86
- assert_equal 2, new.pos
87
-
88
- new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
89
- assert_equal 3, new.pos
90
-
91
- new_noup = ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass') }
92
- assert_equal_or_nil $default_position,new_noup.pos
93
-
94
- new4 = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
95
- assert_equal 4, new4.pos
96
-
97
- new4.insert_at(3)
98
- assert_equal 3, new4.pos
99
-
100
- new.reload
101
- assert_equal 4, new.pos
102
-
103
- new.insert_at(2)
104
- assert_equal 2, new.pos
105
-
106
- new4.reload
107
- assert_equal 4, new4.pos
108
-
109
- new5 = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
110
- assert_equal 5, new5.pos
111
-
112
- new5.insert_at(1)
113
- assert_equal 1, new5.pos
114
-
115
- new4.reload
116
- assert_equal 5, new4.pos
117
-
118
- new_noup.reload
119
- assert_equal_or_nil $default_position, new_noup.pos
120
- end
121
-
122
- def test_delete_middle
123
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
124
-
125
- ArrayScopeListMixin.where(id: 2).first.destroy
126
-
127
- assert_equal [1, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
128
-
129
- assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
130
- assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
131
- assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
132
-
133
- ArrayScopeListMixin.where(id: 1).first.destroy
134
-
135
- assert_equal [3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
136
-
137
- assert_equal 1, ArrayScopeListMixin.where(id: 3).first.pos
138
- assert_equal 2, ArrayScopeListMixin.where(id: 4).first.pos
139
-
140
- ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.where(id: 3).first.destroy }
141
-
142
- assert_equal [4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
143
-
144
- assert_equal 2, ArrayScopeListMixin.where(id: 4).first.pos
145
- end
146
-
147
- def test_remove_from_list_should_then_fail_in_list?
148
- assert_equal true, ArrayScopeListMixin.where(id: 1).first.in_list?
149
- ArrayScopeListMixin.where(id: 1).first.remove_from_list
150
- assert_equal false, ArrayScopeListMixin.where(id: 1).first.in_list?
151
- end
152
-
153
- def test_remove_from_list_should_set_position_to_nil
154
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
155
-
156
- ArrayScopeListMixin.where(id: 2).first.remove_from_list
157
-
158
- assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
159
- assert_nil ArrayScopeListMixin.where(id: 2).first.pos
160
- assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
161
- assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
162
- end
163
-
164
- def test_remove_before_destroy_does_not_shift_lower_items_twice
165
- assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
166
-
167
- ArrayScopeListMixin.where(id: 2).first.remove_from_list
168
- ArrayScopeListMixin.where(id: 2).first.destroy
169
-
170
- assert_equal [1, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
171
-
172
- assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
173
- assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
174
- assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
175
- end
176
- end
177
- end
data/test/shared_list.rb DELETED
@@ -1,347 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Shared
4
- module List
5
- def setup(mixin = ListMixin, mixinError = ListMixinError, id = :id)
6
- @mixin = mixin
7
- @id = id
8
- @mixinError = mixinError
9
- (1..4).each do |counter|
10
- node = @mixin.new parent_id: 5
11
- node.first_id = counter if @id == :first_id
12
- node.second_id = counter if @id == :first_id
13
- node.pos = counter
14
- node.save!
15
- end
16
- end
17
-
18
- def test_current_position
19
- first_item = @mixin.where(parent_id: 5).first
20
- assert_equal 1, first_item.current_position
21
- first_item.remove_from_list
22
- assert_nil first_item.current_position
23
- end
24
-
25
- def test_reordering
26
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
27
-
28
- @mixin.where(@id => 2).first.move_lower
29
- assert_equal [1, 3, 2, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
30
-
31
- @mixin.where(@id => 2).first.move_higher
32
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
33
-
34
- @mixin.where(@id => 1).first.move_to_bottom
35
- assert_equal [2, 3, 4, 1], @mixin.where(parent_id: 5).order('pos').map(&@id)
36
-
37
- @mixin.where(@id => 1).first.move_to_top
38
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
39
-
40
- @mixin.where(@id => 2).first.move_to_bottom
41
- assert_equal [1, 3, 4, 2], @mixin.where(parent_id: 5).order('pos').map(&@id)
42
-
43
- @mixin.where(@id => 4).first.move_to_top
44
- assert_equal [4, 1, 3, 2], @mixin.where(parent_id: 5).order('pos').map(&@id)
45
- end
46
-
47
- def test_move_to_bottom_with_next_to_last_item
48
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
49
- @mixin.where(@id => 3).first.move_to_bottom
50
- assert_equal [1, 2, 4, 3], @mixin.where(parent_id: 5).order('pos').map(&@id)
51
- end
52
-
53
- def test_next_prev
54
- assert_equal @mixin.where(@id => 2).first, @mixin.where(@id => 1).first.lower_item
55
- assert_nil @mixin.where(@id => 1).first.higher_item
56
- assert_equal @mixin.where(@id => 3).first, @mixin.where(@id => 4).first.higher_item
57
- assert_nil @mixin.where(@id => 4).first.lower_item
58
- end
59
-
60
- def test_injection
61
- item = @mixin.new(parent_id: 1)
62
- assert_equal({ parent_id: 1 }, item.scope_condition)
63
- assert_equal "pos", item.position_column
64
- end
65
-
66
- def test_insert
67
- new = create_record(id: 5, parent_id: 20)
68
- assert_equal 1, new.pos
69
- assert new.first?
70
- assert new.last?
71
-
72
- new = create_record(id: 6, parent_id: 20)
73
- assert_equal 2, new.pos
74
- assert !new.first?
75
- assert new.last?
76
-
77
- new = @mixin.acts_as_list_no_update { create_record(id: 7, parent_id: 20) }
78
- assert_equal_or_nil $default_position, new.pos
79
- assert_equal $default_position.is_a?(Integer), new.first?
80
- assert !new.last?
81
-
82
- new = create_record(id: 8, parent_id: 20)
83
- assert_equal 3, new.pos
84
- assert !new.first?
85
- assert new.last?
86
-
87
- new = create_record(id: 9, parent_id: 0)
88
- assert_equal 1, new.pos
89
- assert new.first?
90
- assert new.last?
91
- end
92
-
93
- def test_insert_at
94
- new = create_record(id: 5, parent_id: 20)
95
- assert_equal 1, new.pos
96
-
97
- new = create_record(id: 6, parent_id: 20)
98
- assert_equal 2, new.pos
99
-
100
- new = create_record(id: 7, parent_id: 20)
101
- assert_equal 3, new.pos
102
-
103
- new_noup = @mixin.acts_as_list_no_update { create_record(id: 8, parent_id: 20) }
104
- assert_equal_or_nil $default_position, new_noup.pos
105
-
106
- new4 = create_record(id: 9, parent_id: 20)
107
- assert_equal 4, new4.pos
108
-
109
- new4.insert_at(3)
110
- assert_equal 3, new4.pos
111
-
112
- new.reload
113
- assert_equal 4, new.pos
114
-
115
- new.insert_at(2)
116
- assert_equal 2, new.pos
117
-
118
- new4.reload
119
- assert_equal 4, new4.pos
120
-
121
- new5 = create_record(id: 10, parent_id: 20)
122
- assert_equal 5, new5.pos
123
-
124
- new5.insert_at(1)
125
- assert_equal 1, new5.pos
126
-
127
- new4.reload
128
- assert_equal 5, new4.pos
129
-
130
- new_noup.reload
131
- assert_equal_or_nil $default_position, new_noup.pos
132
-
133
- last1 = @mixin.where('pos IS NOT NULL').order('pos').last
134
- last2 = @mixin.where('pos IS NOT NULL').order('pos').last
135
- last1.insert_at(1)
136
- last2.insert_at(1)
137
- pos_list = @mixin.where(parent_id: 20).order("pos ASC#{' NULLS FIRST' if ENV['DB'] == 'postgresql'}").map(&:pos)
138
- assert_equal [$default_position, 1, 2, 3, 4, 5], pos_list
139
- end
140
-
141
- def test_insert_at_after_dup
142
- new1 = create_record(id: 5, parent_id: 20)
143
- new2 = create_record(id: 6, parent_id: 20)
144
- new3 = create_record(id: 7, parent_id: 20)
145
-
146
- duped = new1.dup
147
- duped.first_id = 8 if @id == :first_id
148
- duped.second_id = 8 if @id == :first_id
149
- duped.insert_at(1)
150
- [new1, new2, new3, duped].map(&:reload)
151
-
152
- assert_equal [1, 2, 3, 4], [duped.pos, new1.pos, new2.pos, new3.pos]
153
- end
154
-
155
- def test_delete_middle
156
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
157
-
158
- @mixin.where(@id => 2).first.destroy
159
- assert_equal [1, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
160
-
161
- assert_equal 1, @mixin.where(@id => 1).first.pos
162
- assert_equal 2, @mixin.where(@id => 3).first.pos
163
- assert_equal 3, @mixin.where(@id => 4).first.pos
164
-
165
- @mixin.where(@id => 1).first.destroy
166
-
167
- assert_equal [3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
168
-
169
- assert_equal 1, @mixin.where(@id => 3).first.pos
170
- assert_equal 2, @mixin.where(@id => 4).first.pos
171
-
172
- @mixin.acts_as_list_no_update { @mixin.where(@id => 3).first.destroy }
173
-
174
- assert_equal [4], @mixin.where(parent_id: 5).order('pos').map(&@id)
175
-
176
- assert_equal 2, @mixin.where(@id => 4).first.pos
177
- end
178
-
179
- def test_with_string_based_scope
180
- new = ListWithStringScopeMixin.create(parent_id: 500)
181
- assert_equal 1, new.pos
182
- assert new.first?
183
- assert new.last?
184
- end
185
-
186
- def test_nil_scope
187
- new1, new2, new3 = create_record(id: 5), create_record(id: 6), create_record(id: 7)
188
- new2.move_higher
189
- assert_equal [new2, new1, new3].map(&@id), @mixin.where(parent_id: nil).order('pos').map(&@id)
190
- end
191
-
192
- def test_update_position_when_scope_changes
193
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
194
- create_record(id: 5, parent_id: 6)
195
-
196
- @mixin.where(@id => 2).first.move_within_scope(6)
197
-
198
- assert_equal 2, @mixin.where(@id => 2).first.pos
199
-
200
- assert_equal [1, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
201
-
202
- assert_equal 1, @mixin.where(@id => 1).first.pos
203
- assert_equal 2, @mixin.where(@id => 3).first.pos
204
- assert_equal 3, @mixin.where(@id => 4).first.pos
205
-
206
- @mixin.where(@id => 2).first.move_within_scope(5)
207
- assert_equal [1, 3, 4, 2], @mixin.where(parent_id: 5).order('pos').map(&@id)
208
- end
209
-
210
- def test_remove_from_list_should_then_fail_in_list?
211
- assert_equal true, @mixin.where(@id => 1).first.in_list?
212
- @mixin.where(@id => 1).first.remove_from_list
213
- assert_equal false, @mixin.where(@id => 1).first.in_list?
214
- end
215
-
216
- def test_remove_from_list_should_set_position_to_nil
217
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
218
-
219
- @mixin.where(@id => 2).first.remove_from_list
220
-
221
- assert_equal 1, @mixin.where(@id => 1).first.pos
222
- assert_nil @mixin.where(@id => 2).first.pos
223
- assert_equal 2, @mixin.where(@id => 3).first.pos
224
- assert_equal 3, @mixin.where(@id => 4).first.pos
225
- end
226
-
227
- def test_remove_before_destroy_does_not_shift_lower_items_twice
228
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
229
-
230
- @mixin.where(@id => 2).first.remove_from_list
231
- @mixin.where(@id => 2).first.destroy
232
-
233
- assert_equal [1, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
234
-
235
- assert_equal 1, @mixin.where(@id => 1).first.pos
236
- assert_equal 2, @mixin.where(@id => 3).first.pos
237
- assert_equal 3, @mixin.where(@id => 4).first.pos
238
- end
239
-
240
- def test_before_destroy_callbacks_do_not_update_position_to_nil_before_deleting_the_record
241
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
242
-
243
- # We need to trigger all the before_destroy callbacks without actually
244
- # destroying the record so we can see the effect the callbacks have on
245
- # the record.
246
- list = @mixin.where(@id => 2).first
247
- if list.respond_to?(:run_callbacks)
248
- list.run_callbacks(:destroy)
249
- else
250
- list.send(:callback, :before_destroy)
251
- end
252
-
253
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
254
-
255
- assert_equal 1, @mixin.where(@id => 1).first.pos
256
- assert_equal 2, @mixin.where(@id => 2).first.pos
257
- assert_equal 2, @mixin.where(@id => 3).first.pos
258
- assert_equal 3, @mixin.where(@id => 4).first.pos
259
- end
260
-
261
- def test_before_create_callback_adds_to_bottom
262
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
263
-
264
- new = create_record(id: 5, parent_id: 5)
265
- assert_equal 5, new.pos
266
- assert !new.first?
267
- assert new.last?
268
-
269
- assert_equal [1, 2, 3, 4, 5], @mixin.where(parent_id: 5).order('pos').map(&@id)
270
- end
271
-
272
- def test_before_create_callback_adds_to_given_position
273
- assert_equal [1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
274
- new = @mixin.new(@id => 5, parent_id: 5)
275
- new.second_id = 5 if @id == :first_id
276
- new.pos = 1
277
- new.save!
278
- assert_equal 1, new.pos
279
- assert new.first?
280
- assert !new.last?
281
-
282
- assert_equal [5, 1, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
283
-
284
- new6 = @mixin.new(@id => 6, parent_id: 5)
285
- new6.second_id = 6 if @id == :first_id
286
- new6.pos = 3
287
- new6.save!
288
- assert_equal 3, new6.pos
289
- assert !new6.first?
290
- assert !new6.last?
291
-
292
- assert_equal [5, 1, 6, 2, 3, 4], @mixin.where(parent_id: 5).order('pos').map(&@id)
293
-
294
- new = @mixin.new(@id => 7, parent_id: 5)
295
- new.second_id = 7 if @id == :first_id
296
- new.pos = 3
297
- @mixin.acts_as_list_no_update { new.save! }
298
- assert_equal 3, new.pos
299
- assert_equal 3, new6.pos
300
- assert !new.first?
301
- assert !new.last?
302
-
303
- assert_equal [5, 1, 6, 7, 2, 3, 4], @mixin.where(parent_id: 5).order("pos, #{@id}").map(&@id)
304
- end
305
-
306
- def test_non_persisted_records_dont_get_lock_called
307
- new = @mixin.new(@id => 5, parent_id: 5)
308
- new.second_id = 6 if @id == :first_id
309
- new.destroy
310
- end
311
-
312
- def test_invalid_records_dont_get_inserted
313
- new = @mixinError.new(@id => 5, parent_id: 5, state: nil)
314
- new.second_id = 6 if @id == :first_id
315
- assert !new.valid?
316
- new.insert_at(1)
317
- assert !new.persisted?
318
- end
319
-
320
- def test_invalid_records_raise_error_with_insert_at!
321
- new = @mixinError.new(@id => 5, parent_id: 5, state: nil)
322
- new.second_id = 5 if @id == :first_id
323
- assert !new.valid?
324
- assert_raises ActiveRecord::RecordInvalid do
325
- new.insert_at!(1)
326
- end
327
- end
328
-
329
- def test_find_or_create_doesnt_raise_deprecation_warning
330
- assert_no_deprecation_warning_raised_by('ActiveRecord deprecation warning raised when using `find_or_create_by` when we didn\'t expect it') do
331
- @mixin.where(parent_id: 5).find_or_create_by(pos: 5) do |new|
332
- new.first_id = 5 if @id == :first_id
333
- new.second_id = 5 if @id == :first_id
334
- end
335
- end
336
- end
337
-
338
- private
339
-
340
- def create_record(opts)
341
- attrs = { parent_id: opts[:parent_id] }
342
- attrs[:first_id] = opts[:id] if @id == :first_id
343
- attrs[:second_id] = opts[:id] if @id == :first_id
344
- @mixin.create(attrs)
345
- end
346
- end
347
- end