Class: JSONAPI::Resource
- Inherits:
-
Object
- Object
- JSONAPI::Resource
- Includes:
- Callbacks
- Defined in:
- lib/jsonapi/resource.rb
Constant Summary collapse
- @@resource_types =
{}
Class Attribute Summary collapse
-
._allowed_filters ⇒ Object
Returns the value of attribute _allowed_filters.
-
._associations ⇒ Object
Returns the value of attribute _associations.
-
._attributes ⇒ Object
Returns the value of attribute _attributes.
-
._paginator ⇒ Object
Returns the value of attribute _paginator.
-
._type ⇒ Object
Returns the value of attribute _type.
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
Class Method Summary collapse
- ._allowed_filter?(filter) ⇒ Boolean
- ._as_parent_key ⇒ Object
- ._association(type) ⇒ Object
-
._attribute_options(attr) ⇒ Object
quasi private class methods.
- ._has_association?(type) ⇒ Boolean
- ._model_class ⇒ Object
- ._model_name ⇒ Object
- ._primary_key ⇒ Object
- ._resource_name_from_type(type) ⇒ Object
- ._updateable_associations ⇒ Object
- .apply_filter(records, filter, value) ⇒ Object
- .apply_filters(records, filters) ⇒ Object
- .apply_pagination(records, paginator) ⇒ Object
- .apply_sort(records, order_options) ⇒ Object
- .attribute(attr, options = {}) ⇒ Object
-
.attributes(*attrs) ⇒ Object
Methods used in defining a resource class.
- .construct_order_options(sort_params) ⇒ Object
- .create(context) ⇒ Object
- .create_model ⇒ Object
-
.createable_fields(context = nil) ⇒ Object
Override in your resource to filter the createable keys.
- .default_attribute_options ⇒ Object
- .fields ⇒ Object
- .filter(attr) ⇒ Object
- .filters(*attrs) ⇒ Object
-
.find(filters, options = {}) ⇒ Object
Override this method if you have more complex requirements than this basic find method provides.
- .find_by_key(key, options = {}) ⇒ Object
- .has_many(*attrs) ⇒ Object
- .has_one(*attrs) ⇒ Object
- .inherited(base) ⇒ Object
- .is_filter_association?(filter) ⇒ Boolean
- .model_name(model) ⇒ Object
- .module_path ⇒ Object
- .paginator(paginator) ⇒ Object
- .primary_key(key) ⇒ Object
-
.records(options = {}) ⇒ Object
Override this method if you want to customize the relation for finder methods (find, find_by_key).
- .resource_for(type) ⇒ Object
- .routing_options(options) ⇒ Object
- .routing_resource_options ⇒ Object
-
.sortable_fields(context = nil) ⇒ Object
Override in your resource to filter the sortable keys.
-
.updateable_fields(context = nil) ⇒ Object
Override in your resource to filter the updateable keys.
-
.verify_association_filter(filter, raw, context = nil) ⇒ Object
override to allow for custom association logic, such as uuids, multiple keys or permission checks on keys.
-
.verify_custom_filter(filter, value, context = nil) ⇒ Object
override to allow for custom filters.
- .verify_filter(filter, raw, context = nil) ⇒ Object
- .verify_filters(filters, context = nil) ⇒ Object
-
.verify_key(key, context = nil) ⇒ Object
override to allow for key processing and checking.
-
.verify_keys(keys, context = nil) ⇒ Object
override to allow for key processing and checking.
Instance Method Summary collapse
- #change(callback) ⇒ Object
- #create_has_many_links(association_type, association_key_values) ⇒ Object
-
#fetchable_fields ⇒ Object
Override this on a resource instance to override the fetchable keys.
- #id ⇒ Object
-
#initialize(model, context = nil) ⇒ Resource
constructor
A new instance of Resource.
- #is_new? ⇒ Boolean
-
#records_for(association_name, options = {}) ⇒ Object
Override this on a resource to customize how the associated records are fetched for a model.
- #remove ⇒ Object
- #remove_has_many_link(association_type, key) ⇒ Object
- #remove_has_one_link(association_type) ⇒ Object
- #replace_fields(field_data) ⇒ Object
- #replace_has_many_links(association_type, association_key_values) ⇒ Object
- #replace_has_one_link(association_type, association_key_value) ⇒ Object
Methods included from Callbacks
Constructor Details
#initialize(model, context = nil) ⇒ Resource
Returns a new instance of Resource.
26 27 28 29 |
# File 'lib/jsonapi/resource.rb', line 26 def initialize(model, context = nil) @model = model @context = context end |
Class Attribute Details
._allowed_filters ⇒ Object
Returns the value of attribute _allowed_filters.
217 218 219 |
# File 'lib/jsonapi/resource.rb', line 217 def _allowed_filters @_allowed_filters end |
._associations ⇒ Object
Returns the value of attribute _associations.
217 218 219 |
# File 'lib/jsonapi/resource.rb', line 217 def _associations @_associations end |
._attributes ⇒ Object
Returns the value of attribute _attributes.
217 218 219 |
# File 'lib/jsonapi/resource.rb', line 217 def _attributes @_attributes end |
._paginator ⇒ Object
Returns the value of attribute _paginator.
217 218 219 |
# File 'lib/jsonapi/resource.rb', line 217 def _paginator @_paginator end |
._type ⇒ Object
Returns the value of attribute _type.
217 218 219 |
# File 'lib/jsonapi/resource.rb', line 217 def _type @_type end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
11 12 13 |
# File 'lib/jsonapi/resource.rb', line 11 def context @context end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
12 13 14 |
# File 'lib/jsonapi/resource.rb', line 12 def model @model end |
Class Method Details
._allowed_filter?(filter) ⇒ Boolean
478 479 480 |
# File 'lib/jsonapi/resource.rb', line 478 def _allowed_filter?(filter) _allowed_filters.include?(filter) end |
._as_parent_key ⇒ Object
449 450 451 |
# File 'lib/jsonapi/resource.rb', line 449 def _as_parent_key @_as_parent_key ||= "#{_type.to_s.singularize}_#{_primary_key}" end |
._association(type) ⇒ Object
436 437 438 439 |
# File 'lib/jsonapi/resource.rb', line 436 def _association(type) type = type.to_sym @_associations[type] end |
._attribute_options(attr) ⇒ Object
quasi private class methods
418 419 420 |
# File 'lib/jsonapi/resource.rb', line 418 def (attr) .merge(@_attributes[attr]) end |
._has_association?(type) ⇒ Boolean
431 432 433 434 |
# File 'lib/jsonapi/resource.rb', line 431 def _has_association?(type) type = type.to_s @_associations.has_key?(type.singularize.to_sym) || @_associations.has_key?(type.pluralize.to_sym) end |
._model_class ⇒ Object
474 475 476 |
# File 'lib/jsonapi/resource.rb', line 474 def _model_class @model ||= _model_name.to_s.safe_constantize end |
._model_name ⇒ Object
441 442 443 |
# File 'lib/jsonapi/resource.rb', line 441 def _model_name @_model_name ||= self.name.demodulize.sub(/Resource$/, '') end |
._primary_key ⇒ Object
445 446 447 |
# File 'lib/jsonapi/resource.rb', line 445 def _primary_key @_primary_key ||= :id end |
._resource_name_from_type(type) ⇒ Object
457 458 459 460 461 462 463 464 |
# File 'lib/jsonapi/resource.rb', line 457 def _resource_name_from_type(type) class_name = @@resource_types[type] if class_name.nil? class_name = type.to_s.singularize.camelize + 'Resource' @@resource_types[type] = class_name end return class_name end |
._updateable_associations ⇒ Object
422 423 424 425 426 427 428 429 |
# File 'lib/jsonapi/resource.rb', line 422 def _updateable_associations associations = [] @_associations.each do |key, association| associations.push(key) end associations end |
.apply_filter(records, filter, value) ⇒ Object
314 315 316 |
# File 'lib/jsonapi/resource.rb', line 314 def apply_filter(records, filter, value) records.where(filter => value) end |
.apply_filters(records, filters) ⇒ Object
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/jsonapi/resource.rb', line 318 def apply_filters(records, filters) required_includes = [] filters.each do |filter, value| if _associations.include?(filter) if _associations[filter].is_a?(JSONAPI::Association::HasMany) required_includes.push(filter) records = apply_filter(records, "#{filter}.#{_associations[filter].primary_key}", value) else records = apply_filter(records, "#{_associations[filter].foreign_key}", value) end else records = apply_filter(records, filter, value) end end records.includes(required_includes) end |
.apply_pagination(records, paginator) ⇒ Object
303 304 305 306 307 308 |
# File 'lib/jsonapi/resource.rb', line 303 def apply_pagination(records, paginator) if paginator records = paginator.apply(records) end records end |
.apply_sort(records, order_options) ⇒ Object
310 311 312 |
# File 'lib/jsonapi/resource.rb', line 310 def apply_sort(records, ) records.order() end |
.attribute(attr, options = {}) ⇒ Object
242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/jsonapi/resource.rb', line 242 def attribute(attr, = {}) check_reserved_attribute_name(attr) @_attributes ||= {} @_attributes[attr] = define_method attr do @model.send(attr) end unless method_defined?(attr) define_method "#{attr}=" do |value| @model.send "#{attr}=", value end unless method_defined?("#{attr}=") end |
.attributes(*attrs) ⇒ Object
Methods used in defining a resource class
236 237 238 239 240 |
# File 'lib/jsonapi/resource.rb', line 236 def attributes(*attrs) attrs.each do |attr| attribute(attr) end end |
.construct_order_options(sort_params) ⇒ Object
486 487 488 489 490 |
# File 'lib/jsonapi/resource.rb', line 486 def (sort_params) sort_params.each_with_object({}) { |sort, order_hash| order_hash[sort[:field]] = sort[:direction] } end |
.create(context) ⇒ Object
219 220 221 |
# File 'lib/jsonapi/resource.rb', line 219 def create(context) self.new(self.create_model, context) end |
.create_model ⇒ Object
223 224 225 |
# File 'lib/jsonapi/resource.rb', line 223 def create_model _model_class.new end |
.createable_fields(context = nil) ⇒ Object
Override in your resource to filter the createable keys
290 291 292 |
# File 'lib/jsonapi/resource.rb', line 290 def createable_fields(context = nil) _updateable_associations | _attributes.keys end |
.default_attribute_options ⇒ Object
256 257 258 |
# File 'lib/jsonapi/resource.rb', line 256 def {format: :default} end |
.fields ⇒ Object
299 300 301 |
# File 'lib/jsonapi/resource.rb', line 299 def fields _associations.keys | _attributes.keys end |
.filter(attr) ⇒ Object
276 277 278 |
# File 'lib/jsonapi/resource.rb', line 276 def filter(attr) @_allowed_filters.add(attr.to_sym) end |
.filters(*attrs) ⇒ Object
272 273 274 |
# File 'lib/jsonapi/resource.rb', line 272 def filters(*attrs) @_allowed_filters.merge(attrs) end |
.find(filters, options = {}) ⇒ Object
Override this method if you have more complex requirements than this basic find method provides
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/jsonapi/resource.rb', line 336 def find(filters, = {}) context = [:context] sort_criteria = .fetch(:sort_criteria) { [] } resources = [] records = records() records = apply_filters(records, filters) records = apply_sort(records, (sort_criteria)) records = apply_pagination(records, [:paginator]) records.each do |model| resources.push self.new(model, context) end return resources end |
.find_by_key(key, options = {}) ⇒ Object
354 355 356 357 358 359 360 361 |
# File 'lib/jsonapi/resource.rb', line 354 def find_by_key(key, = {}) context = [:context] model = records().where({_primary_key => key}).first if model.nil? raise JSONAPI::Exceptions::RecordNotFound.new(key) end self.new(model, context) end |
.has_many(*attrs) ⇒ Object
264 265 266 |
# File 'lib/jsonapi/resource.rb', line 264 def has_many(*attrs) _associate(Association::HasMany, *attrs) end |
.has_one(*attrs) ⇒ Object
260 261 262 |
# File 'lib/jsonapi/resource.rb', line 260 def has_one(*attrs) _associate(Association::HasOne, *attrs) end |
.inherited(base) ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/jsonapi/resource.rb', line 195 def inherited(base) base._attributes = (_attributes || {}).dup base._associations = (_associations || {}).dup base._allowed_filters = (_allowed_filters || Set.new).dup type = base.name.demodulize.sub(/Resource$/, '').underscore base._type = type.pluralize.to_sym base.attribute :id, format: :id check_reserved_resource_name(base._type, base.name) end |
.is_filter_association?(filter) ⇒ Boolean
378 379 380 |
# File 'lib/jsonapi/resource.rb', line 378 def is_filter_association?(filter) filter == _type || _associations.include?(filter) end |
.model_name(model) ⇒ Object
268 269 270 |
# File 'lib/jsonapi/resource.rb', line 268 def model_name(model) @_model_name = model.to_sym end |
.module_path ⇒ Object
482 483 484 |
# File 'lib/jsonapi/resource.rb', line 482 def module_path @module_path ||= self.name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : '' end |
.paginator(paginator) ⇒ Object
470 471 472 |
# File 'lib/jsonapi/resource.rb', line 470 def paginator(paginator) @_paginator = paginator end |
.primary_key(key) ⇒ Object
280 281 282 |
# File 'lib/jsonapi/resource.rb', line 280 def primary_key(key) @_primary_key = key.to_sym end |
.records(options = {}) ⇒ Object
Override this method if you want to customize the relation for finder methods (find, find_by_key)
365 366 367 |
# File 'lib/jsonapi/resource.rb', line 365 def records( = {}) _model_class end |
.resource_for(type) ⇒ Object
208 209 210 211 212 213 214 215 |
# File 'lib/jsonapi/resource.rb', line 208 def resource_for(type) resource_name = JSONAPI::Resource._resource_name_from_type(type) resource = resource_name.safe_constantize if resource_name if resource.nil? raise NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)" end resource end |
.routing_options(options) ⇒ Object
227 228 229 |
# File 'lib/jsonapi/resource.rb', line 227 def () = end |
.routing_resource_options ⇒ Object
231 232 233 |
# File 'lib/jsonapi/resource.rb', line 231 def ||= {} end |
.sortable_fields(context = nil) ⇒ Object
Override in your resource to filter the sortable keys
295 296 297 |
# File 'lib/jsonapi/resource.rb', line 295 def sortable_fields(context = nil) _attributes.keys end |
.updateable_fields(context = nil) ⇒ Object
Override in your resource to filter the updateable keys
285 286 287 |
# File 'lib/jsonapi/resource.rb', line 285 def updateable_fields(context = nil) _updateable_associations | _attributes.keys - [_primary_key] end |
.verify_association_filter(filter, raw, context = nil) ⇒ Object
override to allow for custom association logic, such as uuids, multiple keys or permission checks on keys
413 414 415 |
# File 'lib/jsonapi/resource.rb', line 413 def verify_association_filter(filter, raw, context = nil) return filter, raw end |
.verify_custom_filter(filter, value, context = nil) ⇒ Object
override to allow for custom filters
408 409 410 |
# File 'lib/jsonapi/resource.rb', line 408 def verify_custom_filter(filter, value, context = nil) return filter, value end |
.verify_filter(filter, raw, context = nil) ⇒ Object
382 383 384 385 386 387 388 389 390 391 |
# File 'lib/jsonapi/resource.rb', line 382 def verify_filter(filter, raw, context = nil) filter_values = [] filter_values += CSV.parse_line(raw) unless raw.nil? || raw.empty? if is_filter_association?(filter) verify_association_filter(filter, filter_values, context) else verify_custom_filter(filter, filter_values, context) end end |
.verify_filters(filters, context = nil) ⇒ Object
369 370 371 372 373 374 375 376 |
# File 'lib/jsonapi/resource.rb', line 369 def verify_filters(filters, context = nil) verified_filters = {} filters.each do |filter, raw_value| verified_filter = verify_filter(filter, raw_value, context) verified_filters[verified_filter[0]] = verified_filter[1] end verified_filters end |
.verify_key(key, context = nil) ⇒ Object
override to allow for key processing and checking
394 395 396 397 398 |
# File 'lib/jsonapi/resource.rb', line 394 def verify_key(key, context = nil) key && Integer(key) rescue raise JSONAPI::Exceptions::InvalidFieldValue.new(_primary_key, key) end |
.verify_keys(keys, context = nil) ⇒ Object
override to allow for key processing and checking
401 402 403 404 405 |
# File 'lib/jsonapi/resource.rb', line 401 def verify_keys(keys, context = nil) return keys.collect do |key| verify_key(key, context) end end |
Instance Method Details
#change(callback) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/jsonapi/resource.rb', line 39 def change(callback) if @changing run_callbacks callback do yield end else run_callbacks is_new? ? :create : :update do @changing = true run_callbacks callback do yield save if @save_needed end end end end |
#create_has_many_links(association_type, association_key_values) ⇒ Object
61 62 63 64 65 |
# File 'lib/jsonapi/resource.rb', line 61 def create_has_many_links(association_type, association_key_values) change :create_has_many_link do _create_has_many_links(association_type, association_key_values) end end |
#fetchable_fields ⇒ Object
Override this on a resource instance to override the fetchable keys
98 99 100 |
# File 'lib/jsonapi/resource.rb', line 98 def fetchable_fields self.class.fields end |
#id ⇒ Object
31 32 33 |
# File 'lib/jsonapi/resource.rb', line 31 def id model.send(self.class._primary_key) end |
#is_new? ⇒ Boolean
35 36 37 |
# File 'lib/jsonapi/resource.rb', line 35 def is_new? id.nil? end |
#records_for(association_name, options = {}) ⇒ Object
Override this on a resource to customize how the associated records are fetched for a model. Particularly helpful for authoriztion.
104 105 106 |
# File 'lib/jsonapi/resource.rb', line 104 def records_for(association_name, = {}) model.send association_name end |
#remove ⇒ Object
55 56 57 58 59 |
# File 'lib/jsonapi/resource.rb', line 55 def remove run_callbacks :remove do _remove end end |
#remove_has_many_link(association_type, key) ⇒ Object
79 80 81 82 83 |
# File 'lib/jsonapi/resource.rb', line 79 def remove_has_many_link(association_type, key) change :remove_has_many_link do _remove_has_many_link(association_type, key) end end |
#remove_has_one_link(association_type) ⇒ Object
85 86 87 88 89 |
# File 'lib/jsonapi/resource.rb', line 85 def remove_has_one_link(association_type) change :remove_has_one_link do _remove_has_one_link(association_type) end end |
#replace_fields(field_data) ⇒ Object
91 92 93 94 95 |
# File 'lib/jsonapi/resource.rb', line 91 def replace_fields(field_data) change :replace_fields do _replace_fields(field_data) end end |
#replace_has_many_links(association_type, association_key_values) ⇒ Object
67 68 69 70 71 |
# File 'lib/jsonapi/resource.rb', line 67 def replace_has_many_links(association_type, association_key_values) change :replace_has_many_links do _replace_has_many_links(association_type, association_key_values) end end |
#replace_has_one_link(association_type, association_key_value) ⇒ Object
73 74 75 76 77 |
# File 'lib/jsonapi/resource.rb', line 73 def replace_has_one_link(association_type, association_key_value) change :replace_has_one_link do _replace_has_one_link(association_type, association_key_value) end end |