@@ -23,6 +23,38 @@ class Attachment
2323 include Mongoid ::Document
2424 field :file , type : String
2525 end
26+
27+ class Item
28+ include Mongoid ::Document
29+
30+ field :title , type : String
31+
32+ has_and_belongs_to_many :colors , class_name : 'HabtmSpec::Color' , inverse_of : :items
33+
34+ accepts_nested_attributes_for :colors
35+ end
36+
37+ class Beam
38+ include Mongoid ::Document
39+
40+ field :name , type : String
41+ validates :name , presence : true
42+
43+ has_and_belongs_to_many :colors , class_name : 'HabtmSpec::Color' , inverse_of : :beams
44+
45+ accepts_nested_attributes_for :colors
46+ end
47+
48+ class Color
49+ include Mongoid ::Document
50+
51+ field :name , type : String
52+
53+ has_and_belongs_to_many :items , class_name : 'HabtmSpec::Item' , inverse_of : :colors
54+ has_and_belongs_to_many :beams , class_name : 'HabtmSpec::Beam' , inverse_of : :colors
55+
56+ accepts_nested_attributes_for :items , :beams
57+ end
2658end
2759
2860describe 'has_and_belongs_to_many associations' do
@@ -59,4 +91,53 @@ class Attachment
5991 expect { image_block . save! } . not_to raise_error
6092 end
6193 end
94+
95+ context 'with deeply nested trees' do
96+ let ( :item ) { HabtmSpec ::Item . create! ( title : 'Item' ) }
97+ let ( :beam ) { HabtmSpec ::Beam . create! ( name : 'Beam' ) }
98+ let! ( :color ) { HabtmSpec ::Color . create! ( name : 'Red' , items : [ item ] , beams : [ beam ] ) }
99+
100+ let ( :updated_item_title ) { 'Item Updated' }
101+ let ( :updated_beam_name ) { 'Beam Updated' }
102+
103+ context 'with nested attributes' do
104+ let ( :attributes ) do
105+ {
106+ title : updated_item_title ,
107+ colors_attributes : [
108+ {
109+ # no change for color
110+ _id : color . id ,
111+ beams_attributes : [
112+ {
113+ _id : beam . id ,
114+ name : updated_beam_name ,
115+ }
116+ ]
117+ }
118+ ]
119+ }
120+ end
121+
122+ context 'when the beam is invalid' do
123+ let ( :updated_beam_name ) { '' } # invalid value
124+
125+ it 'will not save the parent' do
126+ expect ( item . update ( attributes ) ) . to be_falsey
127+ expect ( item . errors ) . not_to be_empty
128+ expect ( item . reload . title ) . not_to eq ( updated_item_title )
129+ expect ( beam . reload . name ) . not_to eq ( updated_beam_name )
130+ end
131+ end
132+
133+ context 'when the beam is valid' do
134+ it 'will save the parent' do
135+ expect ( item . update ( attributes ) ) . to be_truthy
136+ expect ( item . errors ) . to be_empty
137+ expect ( item . reload . title ) . to eq ( updated_item_title )
138+ expect ( beam . reload . name ) . to eq ( updated_beam_name )
139+ end
140+ end
141+ end
142+ end
62143end
0 commit comments