her 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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