propel_api 0.1.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.
Files changed (30) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +59 -0
  3. data/LICENSE +21 -0
  4. data/README.md +320 -0
  5. data/Rakefile +36 -0
  6. data/lib/generators/propel_api/USAGE +8 -0
  7. data/lib/generators/propel_api/controller/controller_generator.rb +208 -0
  8. data/lib/generators/propel_api/core/base.rb +19 -0
  9. data/lib/generators/propel_api/core/configuration_methods.rb +187 -0
  10. data/lib/generators/propel_api/core/named_base.rb +457 -0
  11. data/lib/generators/propel_api/core/path_generation_methods.rb +45 -0
  12. data/lib/generators/propel_api/core/relationship_inferrer.rb +117 -0
  13. data/lib/generators/propel_api/install/install_generator.rb +343 -0
  14. data/lib/generators/propel_api/resource/resource_generator.rb +433 -0
  15. data/lib/generators/propel_api/templates/config/propel_api.rb.tt +149 -0
  16. data/lib/generators/propel_api/templates/controllers/api_controller_graphiti.rb +79 -0
  17. data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +76 -0
  18. data/lib/generators/propel_api/templates/controllers/example_controller.rb.tt +96 -0
  19. data/lib/generators/propel_api/templates/scaffold/facet_controller_template.rb.tt +80 -0
  20. data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +141 -0
  21. data/lib/generators/propel_api/templates/scaffold/graphiti_controller_template.rb.tt +82 -0
  22. data/lib/generators/propel_api/templates/scaffold/graphiti_model_template.rb.tt +32 -0
  23. data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +493 -0
  24. data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +485 -0
  25. data/lib/generators/propel_api/templates/tests/fixtures_template.yml.tt +250 -0
  26. data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +487 -0
  27. data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +252 -0
  28. data/lib/generators/propel_api/unpack/unpack_generator.rb +304 -0
  29. data/lib/propel_api.rb +3 -0
  30. metadata +95 -0
@@ -0,0 +1,485 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class <%= controller_class_name_with_namespace %>ControllerTest < ActionDispatch::IntegrationTest
6
+
7
+ def setup
8
+ @organization = organizations(:one)
9
+ @user = users(:one)
10
+ @<%= singular_table_name %> = <%= table_name %>(:one)
11
+ @token = @user.generate_jwt_token
12
+ @auth_headers = { 'Authorization' => "Bearer #{@token}" }
13
+
14
+ # Ensure test <%= singular_table_name %> belongs to test user's organization
15
+ @<%= singular_table_name %>.update!(organization: @organization)
16
+ end
17
+
18
+ # === AUTHENTICATION TESTS ===
19
+
20
+ test "should not access index without authentication" do
21
+ get <%= api_route_helper %>_url
22
+ assert_response :unauthorized
23
+
24
+ response_body = JSON.parse(response.body)
25
+ assert_equal "No token provided", response_body["error"]
26
+ end
27
+
28
+ test "should not access index with invalid token" do
29
+ get <%= api_route_helper %>_url, headers: { 'Authorization' => 'Bearer invalid_token' }
30
+ assert_response :unauthorized
31
+
32
+ response_body = JSON.parse(response.body)
33
+ assert_equal "Invalid token", response_body["error"]
34
+ end
35
+
36
+ test "should not access show without authentication" do
37
+ get <%= api_route_helper %>_url(@<%= singular_table_name %>)
38
+ assert_response :unauthorized
39
+ end
40
+
41
+ test "should not create without authentication" do
42
+ assert_no_difference('<%= class_name %>.count') do
43
+ post <%= api_route_helper %>_url, params: { data: valid_<%= singular_table_name %>_params }
44
+ end
45
+ assert_response :unauthorized
46
+ end
47
+
48
+ test "should not update without authentication" do
49
+ patch <%= api_route_helper %>_url(@<%= singular_table_name %>), params: { data: { title: "Updated" } }
50
+ assert_response :unauthorized
51
+ end
52
+
53
+ test "should not destroy without authentication" do
54
+ assert_no_difference('<%= class_name %>.count') do
55
+ delete <%= api_route_helper %>_url(@<%= singular_table_name %>)
56
+ end
57
+ assert_response :unauthorized
58
+ end
59
+
60
+ # === INDEX TESTS ===
61
+
62
+ test "should get index with authentication" do
63
+ get <%= api_route_helper %>_url, headers: @auth_headers
64
+ assert_response :success
65
+
66
+ response_body = JSON.parse(response.body)
67
+ assert_includes response_body.keys, 'data'
68
+ assert_includes response_body.keys, 'pagination'
69
+
70
+ # Should return array of <%= table_name %>
71
+ assert_kind_of Array, response_body['data']
72
+ end
73
+
74
+ test "should return paginated results" do
75
+ get <%= api_route_helper %>_url, headers: @auth_headers
76
+ assert_response :success
77
+
78
+ response_body = JSON.parse(response.body)
79
+ pagination = response_body['pagination']
80
+
81
+ # Should include pagination metadata
82
+ assert_includes pagination.keys, 'page'
83
+ assert_includes pagination.keys, 'items'
84
+ assert_includes pagination.keys, 'count'
85
+ assert_includes pagination.keys, 'pages'
86
+ assert_includes pagination.keys, 'last'
87
+ assert_includes pagination.keys, 'next'
88
+ assert_includes pagination.keys, 'prev'
89
+ end
90
+
91
+ test "should only show records for user's organization" do
92
+ # Create record for different organization
93
+ other_org = Organization.create!(name: "Other Organization")
94
+ other_<%= singular_table_name %> = <%= class_name %>.create!(
95
+ <% attributes.each_with_index do |attribute, index| -%>
96
+ <% if attribute.name == "organization" && attribute.type == :references -%>
97
+ <%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
98
+ <% elsif attribute.name == "user" && attribute.type == :references -%>
99
+ <%= attribute.name %>: @user<%= ',' if index < attributes.length - 1 %>
100
+ <% elsif attribute.type == :references -%>
101
+ <%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
102
+ <% elsif attribute.type == :string -%>
103
+ <%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
104
+ <% elsif attribute.type == :text -%>
105
+ <%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
106
+ <% elsif attribute.type == :integer -%>
107
+ <%= attribute.name %>: 999<%= ',' if index < attributes.length - 1 %>
108
+ <% elsif attribute.type == :boolean -%>
109
+ <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
110
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
111
+ <%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
112
+ <% else -%>
113
+ <%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
114
+ <% end -%>
115
+ <% end -%>
116
+ )
117
+
118
+ get <%= api_route_helper %>_url, headers: @auth_headers
119
+ assert_response :success
120
+
121
+ response_body = JSON.parse(response.body)
122
+ <%= table_name %>_ids = response_body['data'].map { |item| item['id'] }
123
+
124
+ # Should not include other organization's record
125
+ assert_not_includes <%= table_name %>_ids, other_<%= singular_table_name %>.id
126
+
127
+ # Should include own organization's record
128
+ assert_includes <%= table_name %>_ids, @<%= singular_table_name %>.id
129
+ end
130
+
131
+ # === SHOW TESTS ===
132
+
133
+ test "should show <%= singular_table_name %> with authentication" do
134
+ get <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
135
+ assert_response :success
136
+
137
+ response_body = JSON.parse(response.body)
138
+ assert_includes response_body.keys, 'data'
139
+
140
+ <%= singular_table_name %>_data = response_body['data']
141
+ assert_equal @<%= singular_table_name %>.id, <%= singular_table_name %>_data['id']
142
+ end
143
+
144
+ test "should return 404 for non-existent <%= singular_table_name %>" do
145
+ get <%= api_route_helper %>_url(0), headers: @auth_headers
146
+ assert_response :not_found
147
+ end
148
+
149
+ test "should not show <%= singular_table_name %> from different organization" do
150
+ other_org = Organization.create!(name: "Other Organization")
151
+ other_<%= singular_table_name %> = <%= class_name %>.create!(
152
+ <% attributes.each_with_index do |attribute, index| -%>
153
+ <% if attribute.name == "organization" && attribute.type == :references -%>
154
+ <%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
155
+ <% elsif attribute.name == "user" && attribute.type == :references -%>
156
+ <%= attribute.name %>: @user<%= ',' if index < attributes.length - 1 %>
157
+ <% elsif attribute.type == :references -%>
158
+ <%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
159
+ <% elsif attribute.type == :string -%>
160
+ <%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
161
+ <% elsif attribute.type == :text -%>
162
+ <%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
163
+ <% elsif attribute.type == :integer -%>
164
+ <%= attribute.name %>: 999<%= ',' if index < attributes.length - 1 %>
165
+ <% elsif attribute.type == :boolean -%>
166
+ <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
167
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
168
+ <%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
169
+ <% else -%>
170
+ <%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
171
+ <% end -%>
172
+ <% end -%>
173
+ )
174
+
175
+ get <%= api_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
176
+ assert_response :not_found
177
+ end
178
+
179
+ # === CREATE TESTS ===
180
+
181
+ test "should create <%= singular_table_name %> with valid params" do
182
+ assert_difference('<%= class_name %>.count', 1) do
183
+ post <%= api_route_helper %>_url,
184
+ params: { data: valid_<%= singular_table_name %>_params },
185
+ headers: @auth_headers
186
+ end
187
+
188
+ assert_response :created
189
+
190
+ response_body = JSON.parse(response.body)
191
+ assert_includes response_body.keys, 'data'
192
+
193
+ created_<%= singular_table_name %> = response_body['data']
194
+ assert_equal @organization.id, created_<%= singular_table_name %>['organization']['id']
195
+ assert_equal @user.id, created_<%= singular_table_name %>['user']['id']
196
+ end
197
+
198
+ test "should not create <%= singular_table_name %> with invalid params" do
199
+ assert_no_difference('<%= class_name %>.count') do
200
+ post <%= api_route_helper %>_url,
201
+ params: { data: invalid_<%= singular_table_name %>_params },
202
+ headers: @auth_headers
203
+ end
204
+
205
+ assert_response :unprocessable_entity
206
+
207
+ response_body = JSON.parse(response.body)
208
+ assert_includes response_body.keys, 'errors'
209
+ end
210
+
211
+ test "should auto-assign organization and user on create" do
212
+ params = valid_<%= singular_table_name %>_params
213
+ params.delete(:organization_id) # Don't send organization_id
214
+ params.delete(:user_id) # Don't send user_id
215
+
216
+ assert_difference('<%= class_name %>.count', 1) do
217
+ post <%= api_route_helper %>_url,
218
+ params: { data: params },
219
+ headers: @auth_headers
220
+ end
221
+
222
+ assert_response :created
223
+
224
+ # Should automatically assign current user's organization and user
225
+ created_<%= singular_table_name %> = <%= class_name %>.last
226
+ assert_equal @organization.id, created_<%= singular_table_name %>.organization_id
227
+ assert_equal @user.id, created_<%= singular_table_name %>.user_id
228
+ end
229
+
230
+ # === UPDATE TESTS ===
231
+
232
+ test "should update <%= singular_table_name %> with valid params" do
233
+ <% if attributes.any? { |attr| attr.type == :string && attr.name != "organization" && attr.name != "user" } -%>
234
+ <% string_attr = attributes.find { |attr| attr.type == :string && attr.name != "organization" && attr.name != "user" } -%>
235
+ new_<%= string_attr.name %> = "Updated <%= string_attr.name.humanize %>"
236
+
237
+ patch <%= api_route_helper %>_url(@<%= singular_table_name %>),
238
+ params: { data: { <%= string_attr.name %>: new_<%= string_attr.name %> } },
239
+ headers: @auth_headers
240
+
241
+ assert_response :success
242
+
243
+ @<%= singular_table_name %>.reload
244
+ assert_equal new_<%= string_attr.name %>, @<%= singular_table_name %>.<%= string_attr.name %>
245
+ <% else -%>
246
+ # Update test for <%= singular_table_name %> - customize based on your model's attributes
247
+ patch <%= api_route_helper %>_url(@<%= singular_table_name %>),
248
+ params: { data: valid_<%= singular_table_name %>_params },
249
+ headers: @auth_headers
250
+
251
+ assert_response :success
252
+ <% end -%>
253
+ end
254
+
255
+ test "should not update <%= singular_table_name %> with invalid params" do
256
+ patch <%= api_route_helper %>_url(@<%= singular_table_name %>),
257
+ params: { data: invalid_<%= singular_table_name %>_params },
258
+ headers: @auth_headers
259
+
260
+ assert_response :unprocessable_entity
261
+
262
+ response_body = JSON.parse(response.body)
263
+ assert_includes response_body.keys, 'errors'
264
+ end
265
+
266
+ test "should not update <%= singular_table_name %> from different organization" do
267
+ other_org = Organization.create!(name: "Other Organization")
268
+ other_<%= singular_table_name %> = <%= class_name %>.create!(
269
+ <% attributes.each_with_index do |attribute, index| -%>
270
+ <% if attribute.name == "organization" && attribute.type == :references -%>
271
+ <%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
272
+ <% elsif attribute.name == "user" && attribute.type == :references -%>
273
+ <%= attribute.name %>: @user<%= ',' if index < attributes.length - 1 %>
274
+ <% elsif attribute.type == :references -%>
275
+ <%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
276
+ <% elsif attribute.type == :string -%>
277
+ <%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
278
+ <% elsif attribute.type == :text -%>
279
+ <%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
280
+ <% elsif attribute.type == :integer -%>
281
+ <%= attribute.name %>: 999<%= ',' if index < attributes.length - 1 %>
282
+ <% elsif attribute.type == :boolean -%>
283
+ <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
284
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
285
+ <%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
286
+ <% else -%>
287
+ <%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
288
+ <% end -%>
289
+ <% end -%>
290
+ )
291
+
292
+ patch <%= api_route_helper %>_url(other_<%= singular_table_name %>),
293
+ params: { data: valid_<%= singular_table_name %>_params },
294
+ headers: @auth_headers
295
+
296
+ assert_response :not_found
297
+ end
298
+
299
+ # === DESTROY TESTS ===
300
+
301
+ test "should destroy <%= singular_table_name %>" do
302
+ assert_difference('<%= class_name %>.count', -1) do
303
+ delete <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
304
+ end
305
+
306
+ assert_response :no_content
307
+ end
308
+
309
+ test "should not destroy <%= singular_table_name %> from different organization" do
310
+ other_org = Organization.create!(name: "Other Organization")
311
+ other_<%= singular_table_name %> = <%= class_name %>.create!(
312
+ <% attributes.each_with_index do |attribute, index| -%>
313
+ <% if attribute.name == "organization" && attribute.type == :references -%>
314
+ <%= attribute.name %>: other_org<%= ',' if index < attributes.length - 1 %>
315
+ <% elsif attribute.name == "user" && attribute.type == :references -%>
316
+ <%= attribute.name %>: @user<%= ',' if index < attributes.length - 1 %>
317
+ <% elsif attribute.type == :references -%>
318
+ <%= attribute.name %>: @<%= attribute.name %><%= ',' if index < attributes.length - 1 %>
319
+ <% elsif attribute.type == :string -%>
320
+ <%= attribute.name %>: "Other Org <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
321
+ <% elsif attribute.type == :text -%>
322
+ <%= attribute.name %>: "Other org <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
323
+ <% elsif attribute.type == :integer -%>
324
+ <%= attribute.name %>: 999<%= ',' if index < attributes.length - 1 %>
325
+ <% elsif attribute.type == :boolean -%>
326
+ <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
327
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
328
+ <%= attribute.name %>: 99.99<%= ',' if index < attributes.length - 1 %>
329
+ <% else -%>
330
+ <%= attribute.name %>: "other_value"<%= ',' if index < attributes.length - 1 %>
331
+ <% end -%>
332
+ <% end -%>
333
+ )
334
+
335
+ assert_no_difference('<%= class_name %>.count') do
336
+ delete <%= api_route_helper %>_url(other_<%= singular_table_name %>), headers: @auth_headers
337
+ end
338
+
339
+ assert_response :not_found
340
+ end
341
+
342
+ # === PARAMETER HANDLING TESTS ===
343
+
344
+ test "should accept valid data structure" do
345
+ post <%= api_route_helper %>_url,
346
+ params: { data: valid_<%= singular_table_name %>_params },
347
+ headers: @auth_headers
348
+
349
+ assert_response :created
350
+ end
351
+
352
+ test "should reject params without data wrapper" do
353
+ post <%= api_route_helper %>_url,
354
+ params: valid_<%= singular_table_name %>_params, # No data wrapper
355
+ headers: @auth_headers
356
+
357
+ assert_response :unprocessable_entity
358
+ end
359
+
360
+ test "should filter permitted params only" do
361
+ params_with_extra = valid_<%= singular_table_name %>_params.merge(
362
+ forbidden_field: "should_be_ignored",
363
+ admin_only_field: true
364
+ )
365
+
366
+ post <%= api_route_helper %>_url,
367
+ params: { data: params_with_extra },
368
+ headers: @auth_headers
369
+
370
+ # Should create successfully but ignore forbidden fields
371
+ assert_response :created
372
+
373
+ created_<%= singular_table_name %> = <%= class_name %>.last
374
+ assert_not created_<%= singular_table_name %>.respond_to?(:forbidden_field)
375
+ end
376
+
377
+ # === JSON FACET RESPONSE TESTS ===
378
+
379
+ test "index should return short facet data" do
380
+ get <%= api_route_helper %>_url, headers: @auth_headers
381
+ assert_response :success
382
+
383
+ response_body = JSON.parse(response.body)
384
+ first_item = response_body['data'].first
385
+
386
+ # Should include ID and short facet fields
387
+ assert_includes first_item.keys, 'id'
388
+ <%
389
+ short_attributes = attributes.select do |attr|
390
+ identifying_fields = %w[name title label slug username email status state active published visible enabled]
391
+ simple_types = [:string, :integer, :boolean, :decimal, :float]
392
+ excluded_patterns = /\A(description|content|body|notes|comment|bio|about|summary|created_at|updated_at|deleted_at|password|digest|token|secret|key|salt|encrypted|confirmation|unlock|reset|api_key|access_token|refresh_token)\z/i
393
+ security_patterns = /(password|digest|token|secret|key|salt|encrypted|confirmation|unlock|reset|api_key)/i
394
+
395
+ identifying_fields.include?(attr.name.to_s) ||
396
+ (simple_types.include?(attr.type) &&
397
+ attr.name.to_s !~ excluded_patterns &&
398
+ attr.name.to_s !~ security_patterns &&
399
+ attr.name.to_s.length < 20)
400
+ end
401
+ short_attributes.each do |attribute| -%>
402
+ assert_includes first_item.keys, '<%= attribute.name %>'
403
+ <% end -%>
404
+ end
405
+
406
+ test "show should return details facet data" do
407
+ get <%= api_route_helper %>_url(@<%= singular_table_name %>), headers: @auth_headers
408
+ assert_response :success
409
+
410
+ response_body = JSON.parse(response.body)
411
+ <%= singular_table_name %>_data = response_body['data']
412
+
413
+ # Should include ID and details facet fields
414
+ assert_includes <%= singular_table_name %>_data.keys, 'id'
415
+ <%
416
+ detail_attributes = attributes.reject do |attr|
417
+ excluded_patterns = /\A(created_at|updated_at|deleted_at|password_digest|reset_password_token|confirmation_token|unlock_token)\z/i
418
+ security_patterns = /(password|digest|token|secret|key|salt|encrypted|confirmation|unlock|reset|api_key|access_token|refresh_token)/i
419
+ excluded_types = [:binary]
420
+
421
+ excluded_patterns.match?(attr.name.to_s) ||
422
+ security_patterns.match?(attr.name.to_s) ||
423
+ excluded_types.include?(attr.type)
424
+ end
425
+ detail_attributes.each do |attribute| -%>
426
+ assert_includes <%= singular_table_name %>_data.keys, '<%= attribute.name %>'
427
+ <% end -%>
428
+ end
429
+
430
+ private
431
+
432
+ def valid_<%= singular_table_name %>_params
433
+ {
434
+ <% attributes.each_with_index do |attribute, index| -%>
435
+ <% if attribute.type == :references -%>
436
+ <%= attribute.name %>_id: @<%= attribute.name %>.id<%= ',' if index < attributes.length - 1 %>
437
+ <% elsif attribute.type == :string -%>
438
+ <%= attribute.name %>: "Test <%= attribute.name.humanize %>"<%= ',' if index < attributes.length - 1 %>
439
+ <% elsif attribute.type == :text -%>
440
+ <%= attribute.name %>: "Test <%= attribute.name.humanize %> content"<%= ',' if index < attributes.length - 1 %>
441
+ <% elsif attribute.type == :integer -%>
442
+ <%= attribute.name %>: 42<%= ',' if index < attributes.length - 1 %>
443
+ <% elsif attribute.type == :boolean -%>
444
+ <%= attribute.name %>: true<%= ',' if index < attributes.length - 1 %>
445
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
446
+ <%= attribute.name %>: 123.45<%= ',' if index < attributes.length - 1 %>
447
+ <% else -%>
448
+ <%= attribute.name %>: "test_value"<%= ',' if index < attributes.length - 1 %>
449
+ <% end -%>
450
+ <% end -%>
451
+ }
452
+ end
453
+
454
+ def invalid_<%= singular_table_name %>_params
455
+ {
456
+ <% attributes.each_with_index do |attribute, index| -%>
457
+ <% if attribute.required? -%>
458
+ <% if attribute.type == :references -%>
459
+ <%= attribute.name %>_id: nil<%= ',' if index < attributes.length - 1 %>
460
+ <% elsif attribute.type == :string -%>
461
+ <%= attribute.name %>: nil<%= ',' if index < attributes.length - 1 %>
462
+ <% elsif attribute.type == :text -%>
463
+ <%= attribute.name %>: nil<%= ',' if index < attributes.length - 1 %>
464
+ <% elsif attribute.type == :integer -%>
465
+ <%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
466
+ <% elsif attribute.type == :boolean -%>
467
+ <%= attribute.name %>: nil<%= ',' if index < attributes.length - 1 %>
468
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
469
+ <%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
470
+ <% else -%>
471
+ <%= attribute.name %>: nil<%= ',' if index < attributes.length - 1 %>
472
+ <% end -%>
473
+ <% else -%>
474
+ <% if attribute.type == :integer -%>
475
+ <%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
476
+ <% elsif attribute.type == :decimal || attribute.type == :float -%>
477
+ <%= attribute.name %>: "not_a_number"<%= ',' if index < attributes.length - 1 %>
478
+ <% else -%>
479
+ <%= attribute.name %>: ""<%= ',' if index < attributes.length - 1 %>
480
+ <% end -%>
481
+ <% end -%>
482
+ <% end -%>
483
+ }
484
+ end
485
+ end