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.
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.10.0"
2
+ VERSION = "0.10.1"
3
3
  end
@@ -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
- context "single has_many association" do
10
- before { Foo::User.has_many :comments }
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
- describe "[:has_many]" do
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
- context "multiple has_many associations" do
19
- before do
20
- Foo::User.has_many :comments
21
- Foo::User.has_many :posts
22
- end
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
- describe "[:has_many]" do
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
- context "single has_one association" do
31
- before { Foo::User.has_one :category }
58
+ describe "has_one associations" do
59
+ subject { associations[:has_one] }
32
60
 
33
- describe "[:has_one]" do
34
- subject { super()[:has_one] }
35
- it { is_expected.to eql [{ name: :category, data_key: :category, default: nil, class_name: "Category", path: "/category" }] }
36
- end
37
- end
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
- context "multiple has_one associations" do
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
- describe "[:has_one]" do
46
- subject { super()[:has_one] }
47
- it { is_expected.to eql [{ name: :category, data_key: :category, default: nil, class_name: "Category", path: "/category" }, { name: :role, data_key: :role, default: nil, class_name: "Role", path: "/role" }] }
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
- context "single belongs_to association" do
52
- before { Foo::User.belongs_to :organization }
104
+ describe "belongs_to associations" do
105
+ subject { associations[:belongs_to] }
53
106
 
54
- describe "[:belongs_to]" do
55
- subject { super()[:belongs_to] }
56
- it { is_expected.to eql [{ name: :organization, data_key: :organization, default: nil, class_name: "Organization", foreign_key: "organization_id", path: "/organizations/:id" }] }
57
- end
58
- end
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
- context "multiple belongs_to association" do
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
- describe "[:belongs_to]" do
67
- subject { super()[:belongs_to] }
68
- it { is_expected.to eql [{ name: :organization, data_key: :organization, default: nil, class_name: "Organization", foreign_key: "organization_id", path: "/organizations/:id" }, { name: :family, data_key: :family, default: nil, class_name: "Family", foreign_key: "family_id", path: "/families/:id" }] }
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
- context "single has_many association" do
79
- before { Foo::User.has_many :comments, class_name: "Post", inverse_of: :admin, data_key: :user_comments, default: {} }
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
- describe "[:has_many]" do
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
- context "single has_one association" do
88
- before { Foo::User.has_one :category, class_name: "Topic", foreign_key: "topic_id", data_key: :topic, default: nil }
184
+ describe "has_one associations" do
185
+ subject { associations[:has_one] }
89
186
 
90
- describe "[:has_one]" do
91
- subject { super()[:has_one] }
92
- it { is_expected.to eql [{ name: :category, data_key: :topic, default: nil, class_name: "Topic", foreign_key: "topic_id", path: "/category" }] }
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
- context "single belongs_to association" do
97
- before { Foo::User.belongs_to :organization, class_name: "Business", foreign_key: "org_id", data_key: :org, default: true }
208
+ describe "belongs_to associations" do
209
+ subject { associations[:belongs_to] }
98
210
 
99
- describe "[:belongs_to]" do
100
- subject { super()[:belongs_to] }
101
- it { is_expected.to eql [{ name: :organization, data_key: :org, default: true, class_name: "Business", foreign_key: "org_id", path: "/organizations/:id" }] }
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 { super().object_id }
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 { super()[:has_many] }
119
- it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Post", path: "/comments", inverse_of: nil }] }
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
- let(:user_with_included_data_after_create) { Foo::User.create }
182
- let(:user_with_included_data_after_save_existing) { Foo::User.save_existing(5, name: "Clancy Brown") }
183
- let(:user_with_included_data_after_destroy) { Foo::User.new(id: 5).destroy }
184
- let(:comment_without_included_parent_data) { Foo::Comment.new(id: 7, user_id: 1) }
185
- let(:new_user) { Foo::User.new }
186
-
187
- it "maps an array of included data through has_many" do
188
- expect(@user_with_included_data.comments.first).to be_a(Foo::Comment)
189
- expect(@user_with_included_data.comments.length).to eq(2)
190
- expect(@user_with_included_data.comments.first.id).to eq(2)
191
- expect(@user_with_included_data.comments.first.body).to eq("Tobias, you blow hard!")
192
- end
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
- it "does not refetch the parents models data if they have been fetched before" do
195
- expect(@user_with_included_data.comments.first.user.object_id).to eq(@user_with_included_data.object_id)
196
- end
304
+ let(:user) { Foo::User.find(1) }
305
+ let(:user_params) { user.to_params }
197
306
 
198
- it "does fetch the parent models data only once" do
199
- expect(comment_without_included_parent_data.user.object_id).to eq(comment_without_included_parent_data.user.object_id)
200
- end
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
- it "does fetch the parent models data that was cached if called with parameters" do
203
- expect(comment_without_included_parent_data.user.object_id).not_to eq(comment_without_included_parent_data.user.where(a: 2).object_id)
204
- end
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
- it "uses the given inverse_of key to set the parent model" do
207
- expect(@user_with_included_data.posts.first.admin.object_id).to eq(@user_with_included_data.object_id)
208
- end
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
- it "doesn't attempt to fetch association data for a new resource" do
211
- expect(new_user.comments).to eq([])
212
- expect(new_user.role).to be_nil
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
- it "fetches data that was not included through has_many" do
217
- expect(@user_without_included_data.comments.first).to be_a(Foo::Comment)
218
- expect(@user_without_included_data.comments.length).to eq(2)
219
- expect(@user_without_included_data.comments.first.id).to eq(4)
220
- expect(@user_without_included_data.comments.first.body).to eq("They're having a FIRESALE?")
221
- end
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
- it "fetches has_many data even if it was included, only if called with parameters" do
224
- expect(@user_with_included_data.comments.where(foo_id: 1).length).to eq(1)
225
- end
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
- it "fetches data that was not included through has_many only once" do
228
- expect(@user_without_included_data.comments.first.object_id).to eq(@user_without_included_data.comments.first.object_id)
229
- end
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
- it "fetches data that was cached through has_many if called with parameters" do
232
- expect(@user_without_included_data.comments.first.object_id).not_to eq(@user_without_included_data.comments.where(foo_id: 1).first.object_id)
233
- end
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
- it "fetches data again after being reloaded" do
236
- expect { @user_without_included_data.comments.reload }.to change { @user_without_included_data.comments.first.object_id }
237
- end
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
- it "maps an array of included data through has_one" do
240
- expect(@user_with_included_data.role).to be_a(Foo::Role)
241
- expect(@user_with_included_data.role.object_id).to eq(@user_with_included_data.role.object_id)
242
- expect(@user_with_included_data.role.id).to eq(1)
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
- it "fetches data that was not included through has_one" do
247
- expect(@user_without_included_data.role).to be_a(Foo::Role)
248
- expect(@user_without_included_data.role.id).to eq(2)
249
- expect(@user_without_included_data.role.body).to eq("User")
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
- it "fetches has_one data even if it was included, only if called with parameters" do
253
- expect(@user_with_included_data.role.where(foo_id: 2).id).to eq(3)
254
- end
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
- it "maps an array of included data through belongs_to" do
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
- it "fetches data that was not included through belongs_to" do
263
- expect(@user_without_included_data.organization).to be_a(Foo::Organization)
264
- expect(@user_without_included_data.organization.id).to eq(2)
265
- expect(@user_without_included_data.organization.name).to eq("Bluth Company")
266
- end
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
- it "returns nil if the foreign key is nil" do
269
- expect(@user_without_organization_and_not_persisted.organization).to be_nil
270
- end
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
- it "fetches belongs_to data even if it was included, only if called with parameters" do
273
- expect(@user_with_included_data.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
274
- end
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
- it "can tell if it has a association" do
277
- expect(@user_without_included_data.has_association?(:unknown_association)).to be false
278
- expect(@user_without_included_data.has_association?(:organization)).to be true
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
- it "fetches the resource corresponding to a named association" do
282
- expect(@user_without_included_data.get_association(:unknown_association)).to be_nil
283
- expect(@user_without_included_data.get_association(:organization).name).to eq("Bluth Company")
284
- end
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
- it "pass query string parameters when additional arguments are passed" do
287
- expect(@user_without_included_data.organization.where(admin: true).name).to eq("Bluth Company (admin)")
288
- expect(@user_without_included_data.organization.name).to eq("Bluth Company")
289
- end
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
- it "fetches data with the specified id when calling find" do
292
- comment = @user_without_included_data.comments.find(5)
293
- expect(comment).to be_a(Foo::Comment)
294
- expect(comment.id).to eq(5)
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
- it "'s associations responds to #empty?" do
298
- expect(@user_without_included_data.organization.respond_to?(:empty?)).to be_truthy
299
- expect(@user_without_included_data.organization).not_to be_empty
300
- end
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
- it "includes has_many relationships in params by default" do
303
- params = @user_with_included_data.to_params
304
- expect(params[:comments]).to be_kind_of(Array)
305
- expect(params[:comments].length).to eq(2)
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
- it "includes has_one relationship in params by default" do
309
- params = @user_with_included_data.to_params
310
- expect(params[:role]).to be_kind_of(Hash)
311
- expect(params[:role]).not_to be_empty
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
- it "includes belongs_to relationship in params by default" do
315
- params = @user_with_included_data.to_params
316
- expect(params[:organization]).to be_kind_of(Hash)
317
- expect(params[:organization]).not_to be_empty
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
- [:create, :save_existing, :destroy].each do |type|
321
- context "after #{type}" do
322
- let(:subject) { send("user_with_included_data_after_#{type}") }
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
- it "maps an array of included data through has_many" do
325
- expect(subject.comments.first).to be_a(Foo::Comment)
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
- it "maps an array of included data through has_one" do
332
- expect(subject.role).to be_a(Foo::Role)
333
- expect(subject.role.id).to eq(1)
334
- expect(subject.role.body).to eq("Admin")
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
- it "maps an array of included data through has_many" do
381
- expect(@user_with_included_data.comments.first).to be_a(Foo::Comment)
382
- expect(@user_with_included_data.comments.length).to eq(2)
383
- expect(@user_with_included_data.comments.first.id).to eq(2)
384
- expect(@user_with_included_data.comments.first.body).to eq("Tobias, you blow hard!")
385
- end
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
- it "does not refetch the parents models data if they have been fetched before" do
388
- expect(@user_with_included_data.comments.first.user.object_id).to eq(@user_with_included_data.object_id)
389
- end
566
+ let(:user) { Foo::User.find(1) }
567
+ let(:user_params) { user.to_params }
390
568
 
391
- it "fetches data that was not included through has_many" do
392
- expect(@user_without_included_data.comments.first).to be_a(Foo::Comment)
393
- expect(@user_without_included_data.comments.length).to eq(2)
394
- expect(@user_without_included_data.comments.first.id).to eq(4)
395
- expect(@user_without_included_data.comments.first.body).to eq("They're having a FIRESALE?")
396
- end
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
- it "fetches has_many data even if it was included, only if called with parameters" do
399
- expect(@user_with_included_data.comments.where(foo_id: 1).length).to eq(1)
400
- end
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
- it "maps an array of included data through belongs_to" do
403
- expect(@user_with_included_data.organization).to be_a(Foo::Organization)
404
- expect(@user_with_included_data.organization.id).to eq(1)
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
- it "fetches data that was not included through belongs_to" do
409
- expect(@user_without_included_data.organization).to be_a(Foo::Organization)
410
- expect(@user_without_included_data.organization.id).to eq(1)
411
- expect(@user_without_included_data.organization.name).to eq("Bluth Company Foo")
412
- end
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
- it "fetches belongs_to data even if it was included, only if called with parameters" do
415
- expect(@user_with_included_data.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
416
- end
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
- it "fetches data with the specified id when calling find" do
419
- comment = @user_without_included_data.comments.find(5)
420
- expect(comment).to be_a(Foo::Comment)
421
- expect(comment.id).to eq(5)
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
- it "includes has_many relationships in params by default" do
425
- params = @user_with_included_data.to_params
426
- expect(params[:comments]).to be_kind_of(Array)
427
- expect(params[:comments].length).to eq(2)
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
- it "includes has_one relationships in params by default" do
431
- params = @user_with_included_data.to_params
432
- expect(params[:role]).to be_kind_of(Hash)
433
- expect(params[:role]).not_to be_empty
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
- it "includes belongs_to relationship in params by default" do
437
- params = @user_with_included_data.to_params
438
- expect(params[:organization]).to be_kind_of(Hash)
439
- expect(params[:organization]).not_to be_empty
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
- it "maps an array of included data through belongs_to" do
470
- expect(@user_with_included_data.company).to be_a(Foo::Company)
471
- expect(@user_with_included_data.company.id).to eq(1)
472
- expect(@user_with_included_data.company.name).to eq("Bluth Company Inc.")
473
- end
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
- it "does not map included data if it’s nil" do
476
- expect(@user_with_included_nil_data.company).to be_nil
477
- end
670
+ let(:user) { Foo::User.find(1) }
478
671
 
479
- it "fetches data that was not included through belongs_to" do
480
- expect(@user_without_included_data.company).to be_a(Foo::Company)
481
- expect(@user_without_included_data.company.id).to eq(1)
482
- expect(@user_without_included_data.company.name).to eq("Bluth Company")
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
- it "does not require foreugn key to have nested object" do
486
- expect(@user_with_included_data_but_no_fk.company.name).to eq("Bluth Company Inc.")
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
- @comment = Foo::User.new(id: 10).comments.build(body: "Hello!")
548
- expect(@comment.body).to eq("Hello!")
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
- @user = Foo::User.find(10)
570
- @comment = @user.comments.create(body: "Hello!")
571
- expect(@comment.id).to eq(1)
572
- expect(@comment.body).to eq("Hello!")
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
- it "creates nested models from hash attibutes" do
580
- user = Foo::User.new(name: "vic", comments: [{ text: "hello" }])
581
- expect(user.comments.first.text).to eq("hello")
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
- it "assigns nested models if given as already constructed objects" do
585
- bye = Foo::Comment.new(text: "goodbye")
586
- user = Foo::User.new(name: "vic", comments: [bye])
587
- expect(user.comments.first.text).to eq("goodbye")
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