apicasso 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +226 -223
  3. data/Rakefile +23 -23
  4. data/app/controllers/apicasso/apidocs_controller.rb +309 -299
  5. data/app/controllers/apicasso/application_controller.rb +170 -147
  6. data/app/controllers/apicasso/crud_controller.rb +246 -245
  7. data/app/controllers/concerns/orderable.rb +45 -45
  8. data/app/models/apicasso/ability.rb +38 -38
  9. data/app/models/apicasso/application_record.rb +6 -6
  10. data/app/models/apicasso/key.rb +25 -25
  11. data/app/models/apicasso/request.rb +8 -8
  12. data/config/routes.rb +14 -14
  13. data/lib/apicasso/active_record_extension.rb +0 -44
  14. data/lib/apicasso/engine.rb +13 -13
  15. data/lib/apicasso/version.rb +3 -3
  16. data/lib/apicasso.rb +15 -13
  17. data/lib/generators/apicasso/install/install_generator.rb +25 -25
  18. data/lib/generators/apicasso/install/templates/create_apicasso_tables.rb +20 -20
  19. data/spec/dummy/Gemfile +56 -0
  20. data/spec/dummy/Gemfile.lock +237 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +1 -1
  22. data/spec/dummy/app/models/used_model.rb +42 -0
  23. data/spec/dummy/app/serializers/used_model_serializer.rb +3 -0
  24. data/spec/dummy/bin/rails +5 -0
  25. data/spec/dummy/bin/rake +5 -0
  26. data/spec/dummy/bin/setup +0 -3
  27. data/spec/dummy/bin/spring +17 -0
  28. data/spec/dummy/bin/update +0 -3
  29. data/spec/dummy/config/application.rb +14 -10
  30. data/spec/dummy/config/cable.yml +1 -1
  31. data/spec/dummy/config/credentials.yml.enc +1 -0
  32. data/spec/dummy/config/database.yml +5 -14
  33. data/spec/dummy/config/environments/development.rb +6 -10
  34. data/spec/dummy/config/environments/production.rb +1 -10
  35. data/spec/dummy/config/initializers/cors.rb +16 -0
  36. data/spec/dummy/config/locales/en.yml +7 -32
  37. data/spec/dummy/config/routes.rb +1 -1
  38. data/{db/migrate/20180826141433_create_apicasso_tables.rb → spec/dummy/db/migrate/20180918134607_create_apicasso_tables.rb} +1 -0
  39. data/spec/dummy/db/migrate/20180918141254_create_used_models.rb +44 -0
  40. data/spec/dummy/db/migrate/20180919130152_create_active_storage_tables.active_storage.rb +26 -0
  41. data/spec/dummy/db/migrate/20180920133933_change_used_model_to_validates.rb +7 -0
  42. data/spec/dummy/db/schema.rb +98 -0
  43. data/spec/dummy/db/seeds.rb +56 -0
  44. data/spec/factories/used_model.rb +28 -0
  45. data/spec/models/used_model_spec.rb +35 -0
  46. data/spec/rails_helper.rb +66 -0
  47. data/spec/requests/requests_spec.rb +227 -0
  48. data/spec/spec_helper.rb +7 -9
  49. data/spec/support/factory_bot.rb +3 -0
  50. metadata +83 -64
  51. data/spec/controllers/apicasso/aplication_controller_spec.rb +0 -18
  52. data/spec/controllers/apicasso/crud_controller_spec.rb +0 -107
  53. data/spec/dummy/app/assets/config/manifest.js +0 -3
  54. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  55. data/spec/dummy/app/assets/javascripts/cable.js +0 -13
  56. data/spec/dummy/app/assets/stylesheets/application.css +0 -15
  57. data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
  58. data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
  59. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  60. data/spec/dummy/app/jobs/application_job.rb +0 -2
  61. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  62. data/spec/dummy/app/views/layouts/application.html.erb +0 -15
  63. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  64. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  65. data/spec/dummy/bin/yarn +0 -11
  66. data/spec/dummy/config/initializers/assets.rb +0 -14
  67. data/spec/dummy/config/initializers/content_security_policy.rb +0 -25
  68. data/spec/dummy/config/initializers/cookies_serializer.rb +0 -5
  69. data/spec/dummy/log/development.log +0 -0
  70. data/spec/dummy/public/404.html +0 -67
  71. data/spec/dummy/public/422.html +0 -67
  72. data/spec/dummy/public/500.html +0 -66
  73. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  74. data/spec/dummy/public/apple-touch-icon.png +0 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/factories/apicasso_key.rb +0 -9
  77. data/spec/factories/object.rb +0 -5
  78. data/spec/models/apicasso/key.rb +0 -5
  79. data/spec/routing/appointments_routing_spec.rb +0 -38
@@ -1,245 +1,246 @@
1
- # frozen_string_literal: true
2
-
3
- module Apicasso
4
- # Controller to consume read-only data to be used on client's frontend
5
- class CrudController < Apicasso::ApplicationController
6
- before_action :set_root_resource
7
- before_action :set_object, except: %i[index create schema]
8
- before_action :set_nested_resource, only: %i[nested_index]
9
- before_action :set_records, only: %i[index nested_index]
10
-
11
- include Orderable
12
-
13
- # GET /:resource
14
- # Returns a paginated, ordered and filtered query based response.
15
- # Consider this
16
- # To get all `Channel` sorted by ascending `name` , filtered by
17
- # the ones that have a `domain` that matches exactly `"domain.com"`,
18
- # paginating records 42 per page and retrieving the page 42.
19
- # Example:
20
- # GET /sites?sort=+name,-updated_at&q[domain_eq]=domain.com&page=42&per_page=42
21
- def index
22
- set_access_control_headers
23
- render json: index_json
24
- end
25
-
26
- # GET /:resource/1
27
- # Common behavior for showing a record, with an addition of
28
- # relation/methods including on response
29
- def show
30
- set_access_control_headers
31
- render json: show_json
32
- end
33
-
34
- # PATCH/PUT /:resource/1
35
- # Common behavior for an update API endpoint
36
- def update
37
- authorize_for(action: :update,
38
- resource: resource.name.underscore.to_sym,
39
- object: @object)
40
- if @object.update(object_params)
41
- render json: @object
42
- else
43
- render json: @object.errors, status: :unprocessable_entity
44
- end
45
- end
46
-
47
- # DELETE /:resource/1
48
- # Common behavior for an destroy API endpoint
49
- def destroy
50
- authorize_for(action: :destroy,
51
- resource: resource.name.underscore.to_sym,
52
- object: @object)
53
- if @object.destroy
54
- head :no_content, status: :ok
55
- else
56
- render json: @object.errors, status: :unprocessable_entity
57
- end
58
- end
59
-
60
- # GET /:resource/1/:nested_resource
61
- alias nested_index index
62
-
63
- # POST /:resource
64
- def create
65
- @object = resource.new(object_params)
66
- authorize_for(action: :create,
67
- resource: resource.name.underscore.to_sym,
68
- object: @object)
69
- if @object.save
70
- render json: @object, status: :created
71
- else
72
- render json: @object.errors, status: :unprocessable_entity
73
- end
74
- end
75
-
76
- # OPTIONS /:resource
77
- # OPTIONS /:resource/1/:nested_resource
78
- # Will return a JSON with the schema of the current resource, using
79
- # attribute names as keys and attirbute types as values.
80
- def schema
81
- render json: resource_schema.to_json unless preflight?
82
- end
83
-
84
- private
85
-
86
- # Common setup to stablish which model is the resource of this request
87
- def set_root_resource
88
- @root_resource = params[:resource].classify.constantize
89
- end
90
-
91
- # Common setup to stablish which object this request is querying
92
- def set_object
93
- id = params[:id]
94
- @object = resource.friendly.find(id)
95
- rescue NoMethodError
96
- @object = resource.find(id)
97
- ensure
98
- authorize! :read, @object
99
- end
100
-
101
- # Setup to stablish the nested model to be queried
102
- def set_nested_resource
103
- @nested_resource = @object.send(params[:nested].underscore.pluralize)
104
- end
105
-
106
- # Reutrns root_resource if nested_resource is not set scoped by permissions
107
- def resource
108
- (@nested_resource || @root_resource)
109
- end
110
-
111
- # Used to setup the resource's schema, mapping attributes and it's types
112
- def resource_schema
113
- schemated = {}
114
- resource.columns_hash.each { |key, value| schemated[key] = value.type }
115
- schemated
116
- end
117
-
118
- # Used to setup the records from the selected resource that are
119
- # going to be rendered, if authorized
120
- def set_records
121
- authorize! :read, resource.name.underscore.to_sym
122
- @records = resource.ransack(parsed_query).result
123
- key_scope_records
124
- reorder_records if params[:sort].present?
125
- select_fields if params[:select].present?
126
- include_relations if params[:include].present?
127
- end
128
-
129
- # Selects a fieldset that should be returned, instead of all fields
130
- # from records.
131
- def select_fields
132
- @records = @records.select(*params[:select].split(','))
133
- end
134
-
135
- # Reordering of records which happens when receiving `params[:sort]`
136
- def reorder_records
137
- @records = @records.unscope(:order).order(ordering_params(params))
138
- end
139
-
140
- # Raw paginated records object
141
- def paginated_records
142
- @records
143
- .paginate(page: params[:page], per_page: params[:per_page])
144
- end
145
-
146
- # Records that can be accessed from current Apicasso::Key scope
147
- # permissions
148
- def key_scope_records
149
- @records = @records.accessible_by(current_ability).unscope(:order)
150
- end
151
-
152
- # The response for index action, which can be a pagination of a record collection
153
- # or a grouped count of attributes
154
- def index_json
155
- if params[:group].present?
156
- @records.group(params[:group][:by].split(',')).send(:calculate, params[:group][:calculate], params[:group][:field])
157
- else
158
- collection_response
159
- end
160
- end
161
-
162
- # The response for show action, which can be a fieldset
163
- # or a full response of attributes
164
- def show_json
165
- if params[:select].present?
166
- @object.to_json(include: parsed_include, only: parsed_select)
167
- else
168
- @object.to_json(include: parsed_include)
169
- end
170
- end
171
-
172
- # Parsing of `paginated_records` with pagination variables metadata
173
- def built_paginated
174
- { entries: paginated_records }.merge(pagination_metadata_for(paginated_records))
175
- end
176
-
177
- # All records matching current query and it's total
178
- def built_unpaginated
179
- { entries: @records, total: @records.size }
180
- end
181
-
182
- # Parsed JSON to be used as response payload, with included relations
183
- def include_relations
184
- @records = JSON.parse(included_collection.to_json(include: parsed_include))
185
- rescue ActiveRecord::AssociationNotFoundError, ActiveRecord::ConfigurationError
186
- @records = JSON.parse(@records.to_json(include: parsed_include))
187
- end
188
-
189
- # A way to SQL-include for current param[:include], only if available
190
- def included_collection
191
- @records.includes(parsed_include)
192
- rescue ActiveRecord::AssociationNotFoundError
193
- @records
194
- end
195
-
196
- # Returns the collection checking if it needs pagination
197
- def collection_response
198
- if params[:per_page].to_i < 0
199
- built_unpaginated
200
- else
201
- built_paginated
202
- end
203
- end
204
-
205
- # Only allow a trusted parameter "white list" through,
206
- # based on resource's schema.
207
- def object_params
208
- params.require(resource.name.underscore.to_sym)
209
- .permit(resource_params)
210
- end
211
-
212
- # Resource params mapping, with a twist:
213
- # Including relations as they are needed
214
- def resource_params
215
- built = resource_schema.keys
216
- built += has_one_params if has_one_params.present?
217
- built += has_many_params if has_many_params.present?
218
- built
219
- end
220
-
221
- # A wrapper to has_one relations parameter building
222
- def has_one_params
223
- resource.reflect_on_all_associations(:has_one).map do |one|
224
- if one.class_name.starts_with?('ActiveStorage')
225
- next if one.class_name.ends_with?('Blob')
226
- one.name.to_s.gsub(/(_attachment)$/, '').to_sym
227
- else
228
- one.name
229
- end
230
- end.compact
231
- end
232
-
233
- # A wrapper to has_many parameter building
234
- def has_many_params
235
- resource.reflect_on_all_associations(:has_many).map do |many|
236
- if many.class_name.starts_with?('ActiveStorage')
237
- next if many.class_name.ends_with?('Blob')
238
- { many.name.to_s.gsub(/(_attachments)$/, '').to_sym => [] }
239
- else
240
- { many.name.to_sym => [] }
241
- end
242
- end.compact
243
- end
244
- end
245
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Apicasso
4
+ # Controller to consume read-only data to be used on client's frontend
5
+ class CrudController < Apicasso::ApplicationController
6
+ before_action :set_root_resource
7
+ before_action :set_object, except: %i[index create schema]
8
+ before_action :set_nested_resource, only: %i[nested_index]
9
+ before_action :set_records, only: %i[index nested_index]
10
+ include Orderable
11
+ # GET /:resource
12
+ # Returns a paginated, ordered and filtered query based response.
13
+ # Consider this
14
+ # To get all `Channel` sorted by ascending `name` , filtered by
15
+ # the ones that have a `domain` that matches exactly `"domain.com"`,
16
+ # paginating records 42 per page and retrieving the page 42.
17
+ # Example:
18
+ # GET /sites?sort=+name,-updated_at&q[domain_eq]=domain.com&page=42&per_page=42
19
+ def index
20
+ set_access_control_headers
21
+ render json: index_json
22
+ end
23
+
24
+ # GET /:resource/1
25
+ # Common behavior for showing a record, with an addition of
26
+ # relation/methods including on response
27
+ def show
28
+ set_access_control_headers
29
+ render json: show_json
30
+ end
31
+
32
+ # PATCH/PUT /:resource/1
33
+ # Common behavior for an update API endpoint
34
+ def update
35
+ authorize_for(action: :update,
36
+ resource: resource.name.underscore.to_sym,
37
+ object: @object)
38
+ if @object.update(object_params)
39
+ render json: @object.to_json
40
+ else
41
+ render json: @object.errors, status: :unprocessable_entity
42
+ end
43
+ end
44
+
45
+ # DELETE /:resource/1
46
+ # Common behavior for an destroy API endpoint
47
+ def destroy
48
+ authorize_for(action: :destroy,
49
+ resource: resource.name.underscore.to_sym,
50
+ object: @object)
51
+ if @object.destroy
52
+ head :no_content, status: :ok
53
+ else
54
+ render json: @object.errors, status: :unprocessable_entity
55
+ end
56
+ end
57
+
58
+ # GET /:resource/1/:nested_resource
59
+ alias nested_index index
60
+
61
+ # POST /:resource
62
+ def create
63
+ @object = resource.new(object_params)
64
+ authorize_for(action: :create,
65
+ resource: resource.name.underscore.to_sym,
66
+ object: @object)
67
+ if @object.save
68
+ render json: @object.to_json, status: :created
69
+ else
70
+ render json: @object.errors, status: :unprocessable_entity
71
+ end
72
+ end
73
+
74
+ # OPTIONS /:resource
75
+ # OPTIONS /:resource/1/:nested_resource
76
+ # Will return a JSON with the schema of the current resource, using
77
+ # attribute names as keys and attirbute types as values.
78
+ def schema
79
+ render json: resource_schema.to_json unless preflight?
80
+ end
81
+
82
+ private
83
+
84
+ # Common setup to stablish which model is the resource of this request
85
+ def set_root_resource
86
+ @root_resource = params[:resource].classify.constantize
87
+ end
88
+
89
+ # Common setup to stablish which object this request is querying
90
+ def set_object
91
+ id = params[:id]
92
+ @object = resource.friendly.find(id)
93
+ rescue NoMethodError
94
+ @object = resource.find(id)
95
+ ensure
96
+ authorize! :read, @object
97
+ end
98
+
99
+ # Setup to stablish the nested model to be queried
100
+ def set_nested_resource
101
+ @nested_resource = @object.send(params[:nested].underscore.pluralize)
102
+ end
103
+
104
+ # Reutrns root_resource if nested_resource is not set scoped by permissions
105
+ def resource
106
+ (@nested_resource || @root_resource)
107
+ end
108
+
109
+ # Used to setup the resource's schema, mapping attributes and it's types
110
+ def resource_schema
111
+ schemated = {}
112
+ resource.columns_hash.each { |key, value| schemated[key] = value.type }
113
+ schemated
114
+ end
115
+
116
+ # Used to setup the records from the selected resource that are
117
+ # going to be rendered, if authorized
118
+ def set_records
119
+ authorize! :read, resource.name.underscore.to_sym
120
+ @records = resource.ransack(parsed_query).result
121
+ @object = resource.new
122
+ key_scope_records
123
+ reorder_records if params[:sort].present?
124
+ select_fields if params[:select].present?
125
+ include_relations if params[:include].present?
126
+ end
127
+
128
+ # Selects a fieldset that should be returned, instead of all fields
129
+ # from records.
130
+ def select_fields
131
+ @records = @records.select(*parsed_select)
132
+ end
133
+
134
+ # Reordering of records which happens when receiving `params[:sort]`
135
+ def reorder_records
136
+ @records = @records.unscope(:order).order(ordering_params(params))
137
+ end
138
+
139
+ # Raw paginated records object
140
+ def paginated_records
141
+ @records
142
+ .paginate(page: params[:page], per_page: params[:per_page])
143
+ end
144
+
145
+ # Records that can be accessed from current Apicasso::Key scope
146
+ # permissions
147
+ def key_scope_records
148
+ @records = @records.accessible_by(current_ability).unscope(:order)
149
+ end
150
+
151
+ # The response for index action, which can be a pagination of a record collection
152
+ # or a grouped count of attributes
153
+ def index_json
154
+ if params[:group].present?
155
+ @records.group(params[:group][:by].split(','))
156
+ .send(:calculate,
157
+ params[:group][:calculate],
158
+ params[:group][:field])
159
+ else
160
+ collection_response
161
+ end
162
+ end
163
+
164
+ # The response for show action, which can be a fieldset
165
+ # or a full response of attributes
166
+ def show_json
167
+ json_hash = include_options
168
+ json_hash[:only] = parsed_select if params[:select].present?
169
+ @object.as_json(json_hash)
170
+ end
171
+
172
+ # Parsing of `paginated_records` with pagination variables metadata
173
+ def built_paginated
174
+ { entries: paginated_records.as_json(include_options) }
175
+ .merge(pagination_metadata_for(paginated_records))
176
+ end
177
+
178
+ # All records matching current query and it's total
179
+ def built_unpaginated
180
+ { entries: @records.as_json(include_options),
181
+ total: @records.size }
182
+ end
183
+
184
+ # Parse to include options
185
+ def include_options
186
+ { include: parsed_associations || [],
187
+ methods: parsed_methods || [] }
188
+ end
189
+
190
+ # Parsed JSON to be used as response payload, with included relations
191
+ def include_relations
192
+ @records = @records.includes(parsed_associations)
193
+ end
194
+
195
+ # Returns the collection checking if it needs pagination
196
+ def collection_response
197
+ if params[:per_page].to_i < 0
198
+ built_unpaginated
199
+ else
200
+ built_paginated
201
+ end
202
+ end
203
+
204
+ # Only allow a trusted parameter "white list" through,
205
+ # based on resource's schema.
206
+ def object_params
207
+ params.require(resource.name.underscore.to_sym)
208
+ .permit(resource_params)
209
+ end
210
+
211
+ # Resource params mapping, with a twist:
212
+ # Including relations as they are needed
213
+ def resource_params
214
+ built = resource_schema.keys
215
+ built += has_one_params if has_one_params.present?
216
+ built += has_many_params if has_many_params.present?
217
+ built
218
+ end
219
+
220
+ # A wrapper to has_one relations parameter building
221
+ def has_one_params
222
+ resource.reflect_on_all_associations(:has_one).map do |one|
223
+ if one.class_name.starts_with?('ActiveStorage')
224
+ next if one.class_name.ends_with?('Blob')
225
+
226
+ one.name.to_s.gsub(/(_attachment)$/, '').to_sym
227
+ else
228
+ one.name
229
+ end
230
+ end.compact
231
+ end
232
+
233
+ # A wrapper to has_many parameter building
234
+ def has_many_params
235
+ resource.reflect_on_all_associations(:has_many).map do |many|
236
+ if many.class_name.starts_with?('ActiveStorage')
237
+ next if many.class_name.ends_with?('Blob')
238
+
239
+ { many.name.to_s.gsub(/(_attachments)$/, '').to_sym => [] }
240
+ else
241
+ { many.name.to_sym => [] }
242
+ end
243
+ end.compact
244
+ end
245
+ end
246
+ end
@@ -1,45 +1,45 @@
1
- # frozen_string_literal: true
2
-
3
- # This concern is used to provide abstract ordering based on `params[:sort]`
4
- module Orderable
5
- extend ActiveSupport::Concern
6
- SORT_ORDER = { '+' => :asc, '-' => :desc }.freeze
7
-
8
- # A list of the param names that can be used for ordering the model list
9
- def ordering_params(params)
10
- # For example it retrieves a list of orders in descending order of total_value.
11
- # Within a specific total_value, older orders are ordered first
12
- #
13
- # GET /orders?sort=-total_value,created_at
14
- # ordering_params(params) # => { total_value: :desc, created_at: :asc }
15
- #
16
- # Usage:
17
- # Order.order(ordering_params(params))
18
- ordering = {}
19
- params[:sort].try(:split, ',').try(:each) do |attr|
20
- parsed_attr = parse_attr attr
21
- if model.attribute_names.include?(parsed_attr)
22
- ordering[parsed_attr] = SORT_ORDER[parse_sign attr]
23
- end
24
- end
25
- ordering
26
- end
27
-
28
- private
29
-
30
- # Parsing of attributes to avoid empty starts in case browser passes "+" as " "
31
- def parse_attr(attr)
32
- return attr.gsub(/^\ (.*)/, '\1') if attr.starts_with?(' ')
33
- return attr[1..-1] if attr.match?(/\A[+-]/)
34
- attr
35
- end
36
-
37
- # Ordering sign parse, which separates
38
- def parse_sign(attr)
39
- attr.match?(/\A[+-]/) ? attr.slice!(0) : '+'
40
- end
41
-
42
- def model
43
- (params[:nested] || params[:resource] || controller_name).classify.constantize
44
- end
45
- end
1
+ # frozen_string_literal: true
2
+
3
+ # This concern is used to provide abstract ordering based on `params[:sort]`
4
+ module Orderable
5
+ extend ActiveSupport::Concern
6
+ SORT_ORDER = { '+' => :asc, '-' => :desc }.freeze
7
+
8
+ # A list of the param names that can be used for ordering the model list
9
+ def ordering_params(params)
10
+ # For example it retrieves a list of orders in descending order of total_value.
11
+ # Within a specific total_value, older orders are ordered first
12
+ #
13
+ # GET /orders?sort=-total_value,created_at
14
+ # ordering_params(params) # => { total_value: :desc, created_at: :asc }
15
+ #
16
+ # Usage:
17
+ # Order.order(ordering_params(params))
18
+ ordering = {}
19
+ params[:sort]&.delete(' ').try(:split, ',').try(:each) do |attr|
20
+ parsed_attr = parse_attr attr
21
+ if model.attribute_names.include?(parsed_attr)
22
+ ordering[parsed_attr] = SORT_ORDER[parse_sign attr]
23
+ end
24
+ end
25
+ ordering
26
+ end
27
+
28
+ private
29
+
30
+ # Parsing of attributes to avoid empty starts in case browser passes "+" as " "
31
+ def parse_attr(attr)
32
+ return attr.gsub(/^\ (.*)/, '\1') if attr.starts_with?(' ')
33
+ return attr[1..-1] unless attr.match(/\A[+-]/).nil?
34
+ attr
35
+ end
36
+
37
+ # Ordering sign parse, which separates
38
+ def parse_sign(attr)
39
+ attr.match(/\A[+-]/).nil? ? '+': attr.slice!(0)
40
+ end
41
+
42
+ def model
43
+ (params[:nested] || params[:resource] || controller_name).classify.constantize
44
+ end
45
+ end
@@ -1,38 +1,38 @@
1
- # frozen_string_literal: true
2
-
3
- module Apicasso
4
- # Ability to parse a scope object from Apicasso::Key
5
- class Ability
6
- include CanCan::Ability
7
-
8
- def initialize(key)
9
- key ||= Apicasso::Key.new
10
- cannot :manage, :all
11
- cannot :read, :all
12
- key.scope.each do |permission, klasses_clearances|
13
- klasses_clearances.each do |klass, clearance|
14
- if clearance == true
15
- # Usage:
16
- # To have a key reading all channels and all accouts
17
- # you would have a scope:
18
- # => `{read: {channel: true, accout: true}}`
19
- can permission.to_sym, klass.underscore.singularize.to_sym
20
- can permission.to_sym, klass.classify.constantize
21
- elsif clearance.class == Hash
22
- # Usage:
23
- # To have a key reading all banners from a channel with id 999
24
- # you would have a scope:
25
- # => `{read: {banner: {owner_id: [999]}}}`
26
- can permission.to_sym,
27
- klass.underscore.singularize.to_sym
28
- clearance.each do |by_field, values|
29
- can permission.to_sym,
30
- klass.classify.constantize,
31
- by_field.to_sym => values
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Apicasso
4
+ # Ability to parse a scope object from Apicasso::Key
5
+ class Ability
6
+ include CanCan::Ability
7
+
8
+ def initialize(key)
9
+ key ||= Apicasso::Key.new
10
+ cannot :manage, :all
11
+ cannot :read, :all
12
+ key.scope.each do |permission, klasses_clearances|
13
+ klasses_clearances.each do |klass, clearance|
14
+ if clearance == true
15
+ # Usage:
16
+ # To have a key reading all channels and all accouts
17
+ # you would have a scope:
18
+ # => `{read: {channel: true, accout: true}}`
19
+ can permission.to_sym, klass.underscore.singularize.to_sym
20
+ can permission.to_sym, klass.classify.constantize
21
+ elsif clearance.class == Hash
22
+ # Usage:
23
+ # To have a key reading all banners from a channel with id 999
24
+ # you would have a scope:
25
+ # => `{read: {banner: {owner_id: [999]}}}`
26
+ can permission.to_sym,
27
+ klass.underscore.singularize.to_sym
28
+ clearance.each do |by_field, values|
29
+ can permission.to_sym,
30
+ klass.classify.constantize,
31
+ by_field.to_sym => values
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end