her 0.10.0 → 0.10.1
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/.travis.yml +3 -3
- data/README.md +4 -6
- data/her.gemspec +2 -2
- data/lib/her/model/associations/has_many_association.rb +1 -1
- data/lib/her/model/attributes.rb +30 -22
- data/lib/her/model/introspection.rb +1 -1
- data/lib/her/model/orm.rb +56 -52
- data/lib/her/model/parse.rb +17 -4
- data/lib/her/model/relation.rb +1 -1
- data/lib/her/version.rb +1 -1
- data/spec/model/associations_spec.rb +564 -328
- data/spec/model/attributes_spec.rb +8 -8
- data/spec/model/callbacks_spec.rb +1 -1
- data/spec/model/dirty_spec.rb +41 -1
- data/spec/model/introspection_spec.rb +1 -1
- data/spec/model/orm_spec.rb +22 -4
- data/spec/model/parse_spec.rb +151 -0
- data/spec/model/relation_spec.rb +14 -2
- metadata +11 -11
data/lib/her/version.rb
CHANGED
@@ -4,101 +4,229 @@ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
|
4
4
|
describe Her::Model::Associations do
|
5
5
|
context "setting associations without details" do
|
6
6
|
before { spawn_model "Foo::User" }
|
7
|
-
subject { Foo::User.associations }
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
subject(:associations) { Foo::User.associations }
|
8
|
+
|
9
|
+
describe "has_many associations" do
|
10
|
+
subject { associations[:has_many] }
|
11
|
+
|
12
|
+
context "single" do
|
13
|
+
let(:comments_association) do
|
14
|
+
{
|
15
|
+
name: :comments,
|
16
|
+
data_key: :comments,
|
17
|
+
default: [],
|
18
|
+
class_name: "Comment",
|
19
|
+
path: "/comments",
|
20
|
+
inverse_of: nil
|
21
|
+
}
|
22
|
+
end
|
23
|
+
before { Foo::User.has_many :comments }
|
11
24
|
|
12
|
-
|
13
|
-
subject { super()[:has_many] }
|
14
|
-
it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Comment", path: "/comments", inverse_of: nil }] }
|
25
|
+
it { is_expected.to eql [comments_association] }
|
15
26
|
end
|
16
|
-
end
|
17
27
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
28
|
+
context "multiple" do
|
29
|
+
let(:comments_association) do
|
30
|
+
{
|
31
|
+
name: :comments,
|
32
|
+
data_key: :comments,
|
33
|
+
default: [],
|
34
|
+
class_name: "Comment",
|
35
|
+
path: "/comments",
|
36
|
+
inverse_of: nil
|
37
|
+
}
|
38
|
+
end
|
39
|
+
let(:posts_association) do
|
40
|
+
{
|
41
|
+
name: :posts,
|
42
|
+
data_key: :posts,
|
43
|
+
default: [],
|
44
|
+
class_name: "Post",
|
45
|
+
path: "/posts",
|
46
|
+
inverse_of: nil
|
47
|
+
}
|
48
|
+
end
|
49
|
+
before do
|
50
|
+
Foo::User.has_many :comments
|
51
|
+
Foo::User.has_many :posts
|
52
|
+
end
|
23
53
|
|
24
|
-
|
25
|
-
subject { super()[:has_many] }
|
26
|
-
it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Comment", path: "/comments", inverse_of: nil }, { name: :posts, data_key: :posts, default: [], class_name: "Post", path: "/posts", inverse_of: nil }] }
|
54
|
+
it { is_expected.to eql [comments_association, posts_association] }
|
27
55
|
end
|
28
56
|
end
|
29
57
|
|
30
|
-
|
31
|
-
|
58
|
+
describe "has_one associations" do
|
59
|
+
subject { associations[:has_one] }
|
32
60
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
61
|
+
context "single" do
|
62
|
+
let(:category_association) do
|
63
|
+
{
|
64
|
+
name: :category,
|
65
|
+
data_key: :category,
|
66
|
+
default: nil,
|
67
|
+
class_name: "Category",
|
68
|
+
path: "/category"
|
69
|
+
}
|
70
|
+
end
|
71
|
+
before { Foo::User.has_one :category }
|
38
72
|
|
39
|
-
|
40
|
-
before do
|
41
|
-
Foo::User.has_one :category
|
42
|
-
Foo::User.has_one :role
|
73
|
+
it { is_expected.to eql [category_association] }
|
43
74
|
end
|
44
75
|
|
45
|
-
|
46
|
-
|
47
|
-
|
76
|
+
context "multiple" do
|
77
|
+
let(:category_association) do
|
78
|
+
{
|
79
|
+
name: :category,
|
80
|
+
data_key: :category,
|
81
|
+
default: nil,
|
82
|
+
class_name: "Category",
|
83
|
+
path: "/category"
|
84
|
+
}
|
85
|
+
end
|
86
|
+
let(:role_association) do
|
87
|
+
{
|
88
|
+
name: :role,
|
89
|
+
data_key: :role,
|
90
|
+
default: nil,
|
91
|
+
class_name: "Role",
|
92
|
+
path: "/role"
|
93
|
+
}
|
94
|
+
end
|
95
|
+
before do
|
96
|
+
Foo::User.has_one :category
|
97
|
+
Foo::User.has_one :role
|
98
|
+
end
|
99
|
+
|
100
|
+
it { is_expected.to eql [category_association, role_association] }
|
48
101
|
end
|
49
102
|
end
|
50
103
|
|
51
|
-
|
52
|
-
|
104
|
+
describe "belongs_to associations" do
|
105
|
+
subject { associations[:belongs_to] }
|
53
106
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
107
|
+
context "single" do
|
108
|
+
let(:organization_association) do
|
109
|
+
{
|
110
|
+
name: :organization,
|
111
|
+
data_key: :organization,
|
112
|
+
default: nil,
|
113
|
+
class_name: "Organization",
|
114
|
+
foreign_key: "organization_id",
|
115
|
+
path: "/organizations/:id"
|
116
|
+
}
|
117
|
+
end
|
118
|
+
before { Foo::User.belongs_to :organization }
|
59
119
|
|
60
|
-
|
61
|
-
before do
|
62
|
-
Foo::User.belongs_to :organization
|
63
|
-
Foo::User.belongs_to :family
|
120
|
+
it { is_expected.to eql [organization_association] }
|
64
121
|
end
|
65
122
|
|
66
|
-
|
67
|
-
|
68
|
-
|
123
|
+
context "multiple" do
|
124
|
+
let(:organization_association) do
|
125
|
+
{
|
126
|
+
name: :organization,
|
127
|
+
data_key: :organization,
|
128
|
+
default: nil,
|
129
|
+
class_name: "Organization",
|
130
|
+
foreign_key: "organization_id",
|
131
|
+
path: "/organizations/:id"
|
132
|
+
}
|
133
|
+
end
|
134
|
+
let(:family_association) do
|
135
|
+
{
|
136
|
+
name: :family,
|
137
|
+
data_key: :family,
|
138
|
+
default: nil,
|
139
|
+
class_name: "Family",
|
140
|
+
foreign_key: "family_id",
|
141
|
+
path: "/families/:id"
|
142
|
+
}
|
143
|
+
end
|
144
|
+
before do
|
145
|
+
Foo::User.belongs_to :organization
|
146
|
+
Foo::User.belongs_to :family
|
147
|
+
end
|
148
|
+
|
149
|
+
it { is_expected.to eql [organization_association, family_association] }
|
69
150
|
end
|
70
151
|
end
|
71
152
|
end
|
72
153
|
|
73
154
|
context "setting associations with details" do
|
74
155
|
before { spawn_model "Foo::User" }
|
75
|
-
subject { Foo::User.associations }
|
156
|
+
subject(:associations) { Foo::User.associations }
|
76
157
|
|
77
158
|
context "in base class" do
|
78
|
-
|
79
|
-
|
159
|
+
describe "has_many associations" do
|
160
|
+
subject { associations[:has_many] }
|
161
|
+
|
162
|
+
context "single" do
|
163
|
+
let(:comments_association) do
|
164
|
+
{
|
165
|
+
name: :comments,
|
166
|
+
data_key: :user_comments,
|
167
|
+
default: {},
|
168
|
+
class_name: "Post",
|
169
|
+
path: "/comments",
|
170
|
+
inverse_of: :admin
|
171
|
+
}
|
172
|
+
end
|
173
|
+
before do
|
174
|
+
Foo::User.has_many :comments, class_name: "Post",
|
175
|
+
inverse_of: :admin,
|
176
|
+
data_key: :user_comments,
|
177
|
+
default: {}
|
178
|
+
end
|
80
179
|
|
81
|
-
|
82
|
-
subject { super()[:has_many] }
|
83
|
-
it { is_expected.to eql [{ name: :comments, data_key: :user_comments, default: {}, class_name: "Post", path: "/comments", inverse_of: :admin }] }
|
180
|
+
it { is_expected.to eql [comments_association] }
|
84
181
|
end
|
85
182
|
end
|
86
183
|
|
87
|
-
|
88
|
-
|
184
|
+
describe "has_one associations" do
|
185
|
+
subject { associations[:has_one] }
|
89
186
|
|
90
|
-
|
91
|
-
|
92
|
-
|
187
|
+
context "single" do
|
188
|
+
let(:category_association) do
|
189
|
+
{
|
190
|
+
name: :category,
|
191
|
+
data_key: :topic,
|
192
|
+
default: nil,
|
193
|
+
class_name: "Topic",
|
194
|
+
foreign_key: "topic_id",
|
195
|
+
path: "/category"
|
196
|
+
}
|
197
|
+
end
|
198
|
+
before do
|
199
|
+
Foo::User.has_one :category, class_name: "Topic",
|
200
|
+
foreign_key: "topic_id",
|
201
|
+
data_key: :topic, default: nil
|
202
|
+
end
|
203
|
+
|
204
|
+
it { is_expected.to eql [category_association] }
|
93
205
|
end
|
94
206
|
end
|
95
207
|
|
96
|
-
|
97
|
-
|
208
|
+
describe "belongs_to associations" do
|
209
|
+
subject { associations[:belongs_to] }
|
98
210
|
|
99
|
-
|
100
|
-
|
101
|
-
|
211
|
+
context "single" do
|
212
|
+
let(:organization_association) do
|
213
|
+
{
|
214
|
+
name: :organization,
|
215
|
+
data_key: :org,
|
216
|
+
default: true,
|
217
|
+
class_name: "Business",
|
218
|
+
foreign_key: "org_id",
|
219
|
+
path: "/organizations/:id"
|
220
|
+
}
|
221
|
+
end
|
222
|
+
before do
|
223
|
+
Foo::User.belongs_to :organization, class_name: "Business",
|
224
|
+
foreign_key: "org_id",
|
225
|
+
data_key: :org,
|
226
|
+
default: true
|
227
|
+
end
|
228
|
+
|
229
|
+
it { is_expected.to eql [organization_association] }
|
102
230
|
end
|
103
231
|
end
|
104
232
|
end
|
@@ -107,16 +235,27 @@ describe Her::Model::Associations do
|
|
107
235
|
before { Foo::User.has_many :comments, class_name: "Post" }
|
108
236
|
|
109
237
|
describe "associations accessor" do
|
110
|
-
subject { Class.new(Foo::User).associations }
|
238
|
+
subject(:associations) { Class.new(Foo::User).associations }
|
111
239
|
|
112
240
|
describe "#object_id" do
|
113
|
-
subject {
|
241
|
+
subject { associations.object_id }
|
114
242
|
it { is_expected.not_to eql Foo::User.associations.object_id }
|
115
243
|
end
|
116
244
|
|
117
245
|
describe "[:has_many]" do
|
118
|
-
subject {
|
119
|
-
|
246
|
+
subject { associations[:has_many] }
|
247
|
+
let(:association) do
|
248
|
+
{
|
249
|
+
name: :comments,
|
250
|
+
data_key: :comments,
|
251
|
+
default: [],
|
252
|
+
class_name: "Post",
|
253
|
+
path: "/comments",
|
254
|
+
inverse_of: nil
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
it { is_expected.to eql [association] }
|
120
259
|
end
|
121
260
|
end
|
122
261
|
end
|
@@ -124,33 +263,6 @@ describe Her::Model::Associations do
|
|
124
263
|
|
125
264
|
context "handling associations without details" do
|
126
265
|
before do
|
127
|
-
Her::API.setup url: "https://api.example.com" do |builder|
|
128
|
-
builder.use Her::Middleware::FirstLevelParseJSON
|
129
|
-
builder.use Faraday::Request::UrlEncoded
|
130
|
-
builder.adapter :test do |stub|
|
131
|
-
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", comments: [{ comment: { id: 2, body: "Tobias, you blow hard!", user_id: 1 } }, { comment: { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 } }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 }.to_json] }
|
132
|
-
stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 2 }.to_json] }
|
133
|
-
stub.get("/users/1/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }].to_json] }
|
134
|
-
stub.get("/users/2/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }].to_json] }
|
135
|
-
stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
|
136
|
-
stub.get("/users/2/role") { [200, {}, { id: 2, body: "User" }.to_json] }
|
137
|
-
stub.get("/users/1/role") { [200, {}, { id: 3, body: "User" }.to_json] }
|
138
|
-
stub.get("/users/1/posts") { [200, {}, [{ id: 1, body: "blogging stuff", admin_id: 1 }].to_json] }
|
139
|
-
stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
|
140
|
-
stub.post("/users") { [200, {}, { id: 5, name: "Mr. Krabs", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
141
|
-
stub.put("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
142
|
-
stub.delete("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
143
|
-
|
144
|
-
stub.get("/organizations/2") do |env|
|
145
|
-
if env[:params]["admin"] == "true"
|
146
|
-
[200, {}, { organization: { id: 2, name: "Bluth Company (admin)" } }.to_json]
|
147
|
-
else
|
148
|
-
[200, {}, { organization: { id: 2, name: "Bluth Company" } }.to_json]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
266
|
spawn_model "Foo::User" do
|
155
267
|
has_many :comments, class_name: "Foo::Comment"
|
156
268
|
has_one :role, class_name: "Foo::Role"
|
@@ -172,166 +284,243 @@ describe Her::Model::Associations do
|
|
172
284
|
end
|
173
285
|
|
174
286
|
spawn_model "Foo::Role"
|
175
|
-
|
176
|
-
@user_with_included_data = Foo::User.find(1)
|
177
|
-
@user_without_included_data = Foo::User.find(2)
|
178
|
-
@user_without_organization_and_not_persisted = Foo::User.new(organization_id: nil, name: "Katlin Fünke")
|
179
287
|
end
|
180
288
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
289
|
+
context "with included data" do
|
290
|
+
before(:context) do
|
291
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
292
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
293
|
+
builder.use Faraday::Request::UrlEncoded
|
294
|
+
builder.adapter :test do |stub|
|
295
|
+
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", comments: [{ comment: { id: 2, body: "Tobias, you blow hard!", user_id: 1 } }, { comment: { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 } }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 }.to_json] }
|
296
|
+
stub.get("/users/1/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }].to_json] }
|
297
|
+
stub.get("/users/1/role") { [200, {}, { id: 3, body: "User" }.to_json] }
|
298
|
+
stub.get("/users/1/posts") { [200, {}, [{ id: 1, body: "blogging stuff", admin_id: 1 }].to_json] }
|
299
|
+
stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
193
303
|
|
194
|
-
|
195
|
-
|
196
|
-
end
|
304
|
+
let(:user) { Foo::User.find(1) }
|
305
|
+
let(:user_params) { user.to_params }
|
197
306
|
|
198
|
-
|
199
|
-
|
200
|
-
|
307
|
+
it "maps an array of included data through has_many" do
|
308
|
+
expect(user.comments.first).to be_a(Foo::Comment)
|
309
|
+
expect(user.comments.length).to eq(2)
|
310
|
+
expect(user.comments.first.id).to eq(2)
|
311
|
+
expect(user.comments.first.body).to eq("Tobias, you blow hard!")
|
312
|
+
end
|
201
313
|
|
202
|
-
|
203
|
-
|
204
|
-
|
314
|
+
it "does not refetch the parents models data if they have been fetched before" do
|
315
|
+
expect(user.comments.first.user.object_id).to eq(user.object_id)
|
316
|
+
end
|
205
317
|
|
206
|
-
|
207
|
-
|
208
|
-
|
318
|
+
it "uses the given inverse_of key to set the parent model" do
|
319
|
+
expect(user.posts.first.admin.object_id).to eq(user.object_id)
|
320
|
+
end
|
209
321
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
expect(new_user.organization).to be_nil
|
214
|
-
end
|
322
|
+
it "fetches has_many data even if it was included, only if called with parameters" do
|
323
|
+
expect(user.comments.where(foo_id: 1).length).to eq(1)
|
324
|
+
end
|
215
325
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
326
|
+
it "maps an array of included data through has_one" do
|
327
|
+
expect(user.role).to be_a(Foo::Role)
|
328
|
+
expect(user.role.object_id).to eq(user.role.object_id)
|
329
|
+
expect(user.role.id).to eq(1)
|
330
|
+
expect(user.role.body).to eq("Admin")
|
331
|
+
end
|
222
332
|
|
223
|
-
|
224
|
-
|
225
|
-
|
333
|
+
it "fetches has_one data even if it was included, only if called with parameters" do
|
334
|
+
expect(user.role.where(foo_id: 2).id).to eq(3)
|
335
|
+
end
|
226
336
|
|
227
|
-
|
228
|
-
|
229
|
-
|
337
|
+
it "maps an array of included data through belongs_to" do
|
338
|
+
expect(user.organization).to be_a(Foo::Organization)
|
339
|
+
expect(user.organization.id).to eq(1)
|
340
|
+
expect(user.organization.name).to eq("Bluth Company")
|
341
|
+
end
|
230
342
|
|
231
|
-
|
232
|
-
|
233
|
-
|
343
|
+
it "fetches belongs_to data even if it was included, only if called with parameters" do
|
344
|
+
expect(user.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
|
345
|
+
end
|
234
346
|
|
235
|
-
|
236
|
-
|
237
|
-
|
347
|
+
it "includes has_many relationships in params by default" do
|
348
|
+
expect(user_params[:comments]).to be_kind_of(Array)
|
349
|
+
expect(user_params[:comments].length).to eq(2)
|
350
|
+
end
|
238
351
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
expect(@user_with_included_data.role.body).to eq("Admin")
|
244
|
-
end
|
352
|
+
it "includes has_one relationship in params by default" do
|
353
|
+
expect(user_params[:role]).to be_kind_of(Hash)
|
354
|
+
expect(user_params[:role]).not_to be_empty
|
355
|
+
end
|
245
356
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
357
|
+
it "includes belongs_to relationship in params by default" do
|
358
|
+
expect(user_params[:organization]).to be_kind_of(Hash)
|
359
|
+
expect(user_params[:organization]).not_to be_empty
|
360
|
+
end
|
250
361
|
end
|
251
362
|
|
252
|
-
|
253
|
-
|
254
|
-
|
363
|
+
context "without included data" do
|
364
|
+
before(:context) do
|
365
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
366
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
367
|
+
builder.use Faraday::Request::UrlEncoded
|
368
|
+
builder.adapter :test do |stub|
|
369
|
+
stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 2 }.to_json] }
|
370
|
+
stub.get("/users/2/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }].to_json] }
|
371
|
+
stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
|
372
|
+
stub.get("/users/2/role") { [200, {}, { id: 2, body: "User" }.to_json] }
|
373
|
+
stub.get("/organizations/2") do |env|
|
374
|
+
if env[:params]["admin"] == "true"
|
375
|
+
[200, {}, { organization: { id: 2, name: "Bluth Company (admin)" } }.to_json]
|
376
|
+
else
|
377
|
+
[200, {}, { organization: { id: 2, name: "Bluth Company" } }.to_json]
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
255
383
|
|
256
|
-
|
257
|
-
expect(@user_with_included_data.organization).to be_a(Foo::Organization)
|
258
|
-
expect(@user_with_included_data.organization.id).to eq(1)
|
259
|
-
expect(@user_with_included_data.organization.name).to eq("Bluth Company")
|
260
|
-
end
|
384
|
+
let(:user) { Foo::User.find(2) }
|
261
385
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
386
|
+
it "fetches data that was not included through has_many" do
|
387
|
+
expect(user.comments.first).to be_a(Foo::Comment)
|
388
|
+
expect(user.comments.length).to eq(2)
|
389
|
+
expect(user.comments.first.id).to eq(4)
|
390
|
+
expect(user.comments.first.body).to eq("They're having a FIRESALE?")
|
391
|
+
end
|
267
392
|
|
268
|
-
|
269
|
-
|
270
|
-
|
393
|
+
it "fetches data that was not included through has_many only once" do
|
394
|
+
expect(user.comments.first.object_id).to eq(user.comments.first.object_id)
|
395
|
+
end
|
271
396
|
|
272
|
-
|
273
|
-
|
274
|
-
|
397
|
+
it "fetches data that was cached through has_many if called with parameters" do
|
398
|
+
expect(user.comments.first.object_id).not_to eq(user.comments.where(foo_id: 1).first.object_id)
|
399
|
+
end
|
275
400
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
end
|
401
|
+
it "fetches data again after being reloaded" do
|
402
|
+
expect { user.comments.reload }.to change { user.comments.first.object_id }
|
403
|
+
end
|
280
404
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
405
|
+
it "fetches data that was not included through has_one" do
|
406
|
+
expect(user.role).to be_a(Foo::Role)
|
407
|
+
expect(user.role.id).to eq(2)
|
408
|
+
expect(user.role.body).to eq("User")
|
409
|
+
end
|
285
410
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
411
|
+
it "fetches data that was not included through belongs_to" do
|
412
|
+
expect(user.organization).to be_a(Foo::Organization)
|
413
|
+
expect(user.organization.id).to eq(2)
|
414
|
+
expect(user.organization.name).to eq("Bluth Company")
|
415
|
+
end
|
290
416
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
end
|
417
|
+
it "can tell if it has a association" do
|
418
|
+
expect(user.has_association?(:unknown_association)).to be false
|
419
|
+
expect(user.has_association?(:organization)).to be true
|
420
|
+
end
|
296
421
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
422
|
+
it "fetches the resource corresponding to a named association" do
|
423
|
+
expect(user.get_association(:unknown_association)).to be_nil
|
424
|
+
expect(user.get_association(:organization).name).to eq("Bluth Company")
|
425
|
+
end
|
426
|
+
|
427
|
+
it "pass query string parameters when additional arguments are passed" do
|
428
|
+
expect(user.organization.where(admin: true).name).to eq("Bluth Company (admin)")
|
429
|
+
expect(user.organization.name).to eq("Bluth Company")
|
430
|
+
end
|
301
431
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
432
|
+
it "fetches data with the specified id when calling find" do
|
433
|
+
comment = user.comments.find(5)
|
434
|
+
expect(comment).to be_a(Foo::Comment)
|
435
|
+
expect(comment.id).to eq(5)
|
436
|
+
end
|
437
|
+
|
438
|
+
it "'s associations responds to #empty?" do
|
439
|
+
expect(user.organization.respond_to?(:empty?)).to be_truthy
|
440
|
+
expect(user.organization).not_to be_empty
|
441
|
+
end
|
306
442
|
end
|
307
443
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
444
|
+
context "without included parent data" do
|
445
|
+
before(:context) do
|
446
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
447
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
448
|
+
builder.use Faraday::Request::UrlEncoded
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
let(:comment) { Foo::Comment.new(id: 7, user_id: 1) }
|
453
|
+
|
454
|
+
it "does fetch the parent models data only once" do
|
455
|
+
expect(comment.user.object_id).to eq(comment.user.object_id)
|
456
|
+
end
|
457
|
+
|
458
|
+
it "does fetch the parent models data that was cached if called with parameters" do
|
459
|
+
expect(comment.user.object_id).not_to eq(comment.user.where(a: 2).object_id)
|
460
|
+
end
|
312
461
|
end
|
313
462
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
463
|
+
context "when resource is new" do
|
464
|
+
let(:new_user) { Foo::User.new }
|
465
|
+
|
466
|
+
it "doesn't attempt to fetch association data" do
|
467
|
+
expect(new_user.comments).to eq([])
|
468
|
+
expect(new_user.role).to be_nil
|
469
|
+
expect(new_user.organization).to be_nil
|
470
|
+
end
|
318
471
|
end
|
319
472
|
|
320
|
-
|
321
|
-
|
322
|
-
|
473
|
+
context "when foreign_key is nil" do
|
474
|
+
before do
|
475
|
+
spawn_model "Foo::User" do
|
476
|
+
belongs_to :organization, class_name: "Foo::Organization"
|
477
|
+
end
|
323
478
|
|
324
|
-
|
325
|
-
|
326
|
-
expect(subject.comments.length).to eq(1)
|
327
|
-
expect(subject.comments.first.id).to eq(99)
|
328
|
-
expect(subject.comments.first.body).to eq("Rodríguez, nasibisibusi?")
|
479
|
+
spawn_model "Foo::Organization" do
|
480
|
+
parse_root_in_json true
|
329
481
|
end
|
482
|
+
end
|
330
483
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
484
|
+
let(:user) { Foo::User.new(organization_id: nil, name: "Katlin Fünke") }
|
485
|
+
|
486
|
+
it "returns nil" do
|
487
|
+
expect(user.organization).to be_nil
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
context "after" do
|
492
|
+
before(:context) do
|
493
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
494
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
495
|
+
builder.use Faraday::Request::UrlEncoded
|
496
|
+
builder.adapter :test do |stub|
|
497
|
+
stub.post("/users") { [200, {}, { id: 5, name: "Mr. Krabs", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
498
|
+
stub.put("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
499
|
+
stub.delete("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
let(:user_after_create) { Foo::User.create }
|
505
|
+
let(:user_after_save_existing) { Foo::User.save_existing(5, name: "Clancy Brown") }
|
506
|
+
let(:user_after_destroy) { Foo::User.new(id: 5).destroy }
|
507
|
+
|
508
|
+
[:create, :save_existing, :destroy].each do |type|
|
509
|
+
context "after #{type}" do
|
510
|
+
let(:subject) { send("user_after_#{type}") }
|
511
|
+
|
512
|
+
it "maps an array of included data through has_many" do
|
513
|
+
expect(subject.comments.first).to be_a(Foo::Comment)
|
514
|
+
expect(subject.comments.length).to eq(1)
|
515
|
+
expect(subject.comments.first.id).to eq(99)
|
516
|
+
expect(subject.comments.first.body).to eq("Rodríguez, nasibisibusi?")
|
517
|
+
end
|
518
|
+
|
519
|
+
it "maps an array of included data through has_one" do
|
520
|
+
expect(subject.role).to be_a(Foo::Role)
|
521
|
+
expect(subject.role.id).to eq(1)
|
522
|
+
expect(subject.role.body).to eq("Admin")
|
523
|
+
end
|
335
524
|
end
|
336
525
|
end
|
337
526
|
end
|
@@ -339,19 +528,6 @@ describe Her::Model::Associations do
|
|
339
528
|
|
340
529
|
context "handling associations with details in active_model_serializers format" do
|
341
530
|
before do
|
342
|
-
Her::API.setup url: "https://api.example.com" do |builder|
|
343
|
-
builder.use Her::Middleware::FirstLevelParseJSON
|
344
|
-
builder.use Faraday::Request::UrlEncoded
|
345
|
-
builder.adapter :test do |stub|
|
346
|
-
stub.get("/users/1") { [200, {}, { user: { id: 1, name: "Tobias Fünke", comments: [{ id: 2, body: "Tobias, you blow hard!", user_id: 1 }, { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 } }.to_json] }
|
347
|
-
stub.get("/users/2") { [200, {}, { user: { id: 2, name: "Lindsay Fünke", organization_id: 1 } }.to_json] }
|
348
|
-
stub.get("/users/1/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }] }.to_json] }
|
349
|
-
stub.get("/users/2/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }, { id: 5, body: "Is this the tiny town from Footloose?" }] }.to_json] }
|
350
|
-
stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
|
351
|
-
stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
531
|
spawn_model "Foo::User" do
|
356
532
|
parse_root_in_json true, format: :active_model_serializers
|
357
533
|
has_many :comments, class_name: "Foo::Comment"
|
@@ -372,118 +548,169 @@ describe Her::Model::Associations do
|
|
372
548
|
spawn_model "Foo::Organization" do
|
373
549
|
parse_root_in_json true, format: :active_model_serializers
|
374
550
|
end
|
375
|
-
|
376
|
-
@user_with_included_data = Foo::User.find(1)
|
377
|
-
@user_without_included_data = Foo::User.find(2)
|
378
551
|
end
|
379
552
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
553
|
+
context "with included data" do
|
554
|
+
before(:context) do
|
555
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
556
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
557
|
+
builder.use Faraday::Request::UrlEncoded
|
558
|
+
builder.adapter :test do |stub|
|
559
|
+
stub.get("/users/1") { [200, {}, { user: { id: 1, name: "Tobias Fünke", comments: [{ id: 2, body: "Tobias, you blow hard!", user_id: 1 }, { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 } }.to_json] }
|
560
|
+
stub.get("/users/1/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }] }.to_json] }
|
561
|
+
stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
386
565
|
|
387
|
-
|
388
|
-
|
389
|
-
end
|
566
|
+
let(:user) { Foo::User.find(1) }
|
567
|
+
let(:user_params) { user.to_params }
|
390
568
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
569
|
+
it "maps an array of included data through has_many" do
|
570
|
+
expect(user.comments.first).to be_a(Foo::Comment)
|
571
|
+
expect(user.comments.length).to eq(2)
|
572
|
+
expect(user.comments.first.id).to eq(2)
|
573
|
+
expect(user.comments.first.body).to eq("Tobias, you blow hard!")
|
574
|
+
end
|
397
575
|
|
398
|
-
|
399
|
-
|
400
|
-
|
576
|
+
it "does not refetch the parents models data if they have been fetched before" do
|
577
|
+
expect(user.comments.first.user.object_id).to eq(user.object_id)
|
578
|
+
end
|
401
579
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
expect(@user_with_included_data.organization.name).to eq("Bluth Company")
|
406
|
-
end
|
580
|
+
it "fetches has_many data even if it was included, only if called with parameters" do
|
581
|
+
expect(user.comments.where(foo_id: 1).length).to eq(1)
|
582
|
+
end
|
407
583
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
584
|
+
it "maps an array of included data through belongs_to" do
|
585
|
+
expect(user.organization).to be_a(Foo::Organization)
|
586
|
+
expect(user.organization.id).to eq(1)
|
587
|
+
expect(user.organization.name).to eq("Bluth Company")
|
588
|
+
end
|
413
589
|
|
414
|
-
|
415
|
-
|
416
|
-
|
590
|
+
it "fetches belongs_to data even if it was included, only if called with parameters" do
|
591
|
+
expect(user.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
|
592
|
+
end
|
417
593
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
end
|
594
|
+
it "includes has_many relationships in params by default" do
|
595
|
+
expect(user_params[:comments]).to be_kind_of(Array)
|
596
|
+
expect(user_params[:comments].length).to eq(2)
|
597
|
+
end
|
423
598
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
end
|
599
|
+
it "includes has_one relationships in params by default" do
|
600
|
+
expect(user_params[:role]).to be_kind_of(Hash)
|
601
|
+
expect(user_params[:role]).not_to be_empty
|
602
|
+
end
|
429
603
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
604
|
+
it "includes belongs_to relationship in params by default" do
|
605
|
+
expect(user_params[:organization]).to be_kind_of(Hash)
|
606
|
+
expect(user_params[:organization]).not_to be_empty
|
607
|
+
end
|
434
608
|
end
|
435
609
|
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
610
|
+
context "without included data" do
|
611
|
+
before(:context) do
|
612
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
613
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
614
|
+
builder.use Faraday::Request::UrlEncoded
|
615
|
+
builder.adapter :test do |stub|
|
616
|
+
stub.get("/users/2") { [200, {}, { user: { id: 2, name: "Lindsay Fünke", organization_id: 1 } }.to_json] }
|
617
|
+
stub.get("/users/2/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }, { id: 5, body: "Is this the tiny town from Footloose?" }] }.to_json] }
|
618
|
+
stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
|
619
|
+
stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
let(:user) { Foo::User.find(2) }
|
625
|
+
|
626
|
+
it "fetches data that was not included through has_many" do
|
627
|
+
expect(user.comments.first).to be_a(Foo::Comment)
|
628
|
+
expect(user.comments.length).to eq(2)
|
629
|
+
expect(user.comments.first.id).to eq(4)
|
630
|
+
expect(user.comments.first.body).to eq("They're having a FIRESALE?")
|
631
|
+
end
|
632
|
+
|
633
|
+
it "fetches data that was not included through belongs_to" do
|
634
|
+
expect(user.organization).to be_a(Foo::Organization)
|
635
|
+
expect(user.organization.id).to eq(1)
|
636
|
+
expect(user.organization.name).to eq("Bluth Company Foo")
|
637
|
+
end
|
638
|
+
|
639
|
+
it "fetches data with the specified id when calling find" do
|
640
|
+
comment = user.comments.find(5)
|
641
|
+
expect(comment).to be_a(Foo::Comment)
|
642
|
+
expect(comment.id).to eq(5)
|
643
|
+
end
|
440
644
|
end
|
441
645
|
end
|
442
646
|
|
443
647
|
context "handling associations with details" do
|
444
648
|
before do
|
445
|
-
Her::API.setup url: "https://api.example.com" do |builder|
|
446
|
-
builder.use Her::Middleware::FirstLevelParseJSON
|
447
|
-
builder.use Faraday::Request::UrlEncoded
|
448
|
-
builder.adapter :test do |stub|
|
449
|
-
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." }, organization_id: 1 }.to_json] }
|
450
|
-
stub.get("/users/4") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." } }.to_json] }
|
451
|
-
stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 1 }.to_json] }
|
452
|
-
stub.get("/users/3") { [200, {}, { id: 2, name: "Lindsay Fünke", company: nil }.to_json] }
|
453
|
-
stub.get("/companies/1") { [200, {}, { id: 1, name: "Bluth Company" }.to_json] }
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
649
|
spawn_model "Foo::User" do
|
458
650
|
belongs_to :company, path: "/organizations/:id", foreign_key: :organization_id, data_key: :organization
|
459
651
|
end
|
460
652
|
|
461
653
|
spawn_model "Foo::Company"
|
462
|
-
|
463
|
-
@user_with_included_data = Foo::User.find(1)
|
464
|
-
@user_without_included_data = Foo::User.find(2)
|
465
|
-
@user_with_included_nil_data = Foo::User.find(3)
|
466
|
-
@user_with_included_data_but_no_fk = Foo::User.find(4)
|
467
654
|
end
|
468
655
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
656
|
+
context "with included data" do
|
657
|
+
before(:context) do
|
658
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
659
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
660
|
+
builder.use Faraday::Request::UrlEncoded
|
661
|
+
builder.adapter :test do |stub|
|
662
|
+
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." }, organization_id: 1 }.to_json] }
|
663
|
+
stub.get("/users/4") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." } }.to_json] }
|
664
|
+
stub.get("/users/3") { [200, {}, { id: 2, name: "Lindsay Fünke", company: nil }.to_json] }
|
665
|
+
stub.get("/companies/1") { [200, {}, { id: 1, name: "Bluth Company" }.to_json] }
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
474
669
|
|
475
|
-
|
476
|
-
expect(@user_with_included_nil_data.company).to be_nil
|
477
|
-
end
|
670
|
+
let(:user) { Foo::User.find(1) }
|
478
671
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
672
|
+
it "maps an array of included data through belongs_to" do
|
673
|
+
expect(user.company).to be_a(Foo::Company)
|
674
|
+
expect(user.company.id).to eq(1)
|
675
|
+
expect(user.company.name).to eq("Bluth Company Inc.")
|
676
|
+
end
|
677
|
+
|
678
|
+
context "when included data is nil" do
|
679
|
+
let(:user) { Foo::User.find(3) }
|
680
|
+
|
681
|
+
it "does not map included data" do
|
682
|
+
expect(user.company).to be_nil
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
context "when included data has no foreign_key" do
|
687
|
+
let(:user) { Foo::User.find(4) }
|
688
|
+
|
689
|
+
it "maps included data anyway" do
|
690
|
+
expect(user.company.name).to eq("Bluth Company Inc.")
|
691
|
+
end
|
692
|
+
end
|
483
693
|
end
|
484
694
|
|
485
|
-
|
486
|
-
|
695
|
+
context "without included data" do
|
696
|
+
before(:context) do
|
697
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
698
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
699
|
+
builder.use Faraday::Request::UrlEncoded
|
700
|
+
builder.adapter :test do |stub|
|
701
|
+
stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 1 }.to_json] }
|
702
|
+
stub.get("/companies/1") { [200, {}, { id: 1, name: "Bluth Company" }.to_json] }
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
let(:user) { Foo::User.find(2) }
|
708
|
+
|
709
|
+
it "fetches data that was not included through belongs_to" do
|
710
|
+
expect(user.company).to be_a(Foo::Company)
|
711
|
+
expect(user.company.id).to eq(1)
|
712
|
+
expect(user.company.name).to eq("Bluth Company")
|
713
|
+
end
|
487
714
|
end
|
488
715
|
end
|
489
716
|
|
@@ -543,14 +770,18 @@ describe Her::Model::Associations do
|
|
543
770
|
end
|
544
771
|
|
545
772
|
context "with #build" do
|
773
|
+
let(:comment) { Foo::User.new(id: 10).comments.build(body: "Hello!") }
|
774
|
+
|
546
775
|
it "takes the parent primary key" do
|
547
|
-
|
548
|
-
expect(
|
549
|
-
expect(@comment.user_id).to eq(10)
|
776
|
+
expect(comment.body).to eq("Hello!")
|
777
|
+
expect(comment.user_id).to eq(10)
|
550
778
|
end
|
551
779
|
end
|
552
780
|
|
553
781
|
context "with #create" do
|
782
|
+
let(:user) { Foo::User.find(10) }
|
783
|
+
let(:comment) { user.comments.create(body: "Hello!") }
|
784
|
+
|
554
785
|
before do
|
555
786
|
Her::API.setup url: "https://api.example.com" do |builder|
|
556
787
|
builder.use Her::Middleware::FirstLevelParseJSON
|
@@ -566,25 +797,30 @@ describe Her::Model::Associations do
|
|
566
797
|
end
|
567
798
|
|
568
799
|
it "takes the parent primary key and saves the resource" do
|
569
|
-
|
570
|
-
|
571
|
-
expect(
|
572
|
-
expect(
|
573
|
-
expect(@comment.user_id).to eq(10)
|
574
|
-
expect(@user.comments).to eq([@comment])
|
800
|
+
expect(comment.id).to eq(1)
|
801
|
+
expect(comment.body).to eq("Hello!")
|
802
|
+
expect(comment.user_id).to eq(10)
|
803
|
+
expect(user.comments).to eq([comment])
|
575
804
|
end
|
576
805
|
end
|
577
806
|
|
578
807
|
context "with #new" do
|
579
|
-
|
580
|
-
|
581
|
-
|
808
|
+
let(:user) { Foo::User.new(name: "vic", comments: [comment]) }
|
809
|
+
|
810
|
+
context "using hash attributes" do
|
811
|
+
let(:comment) { { text: "hello" } }
|
812
|
+
|
813
|
+
it "assigns nested models" do
|
814
|
+
expect(user.comments.first.text).to eq("hello")
|
815
|
+
end
|
582
816
|
end
|
583
817
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
818
|
+
context "using constructed objects" do
|
819
|
+
let(:comment) { Foo::Comment.new(text: "goodbye") }
|
820
|
+
|
821
|
+
it "assigns nested models" do
|
822
|
+
expect(user.comments.first.text).to eq("goodbye")
|
823
|
+
end
|
588
824
|
end
|
589
825
|
end
|
590
826
|
end
|