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
- ._updatable_associations ⇒ Object
- .apply_filter(records, filter, value, options = {}) ⇒ Object
- .apply_filters(records, filters, options = {}) ⇒ Object
- .apply_includes(records, directives) ⇒ Object
- .apply_pagination(records, paginator, order_options) ⇒ 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
-
.creatable_fields(context = nil) ⇒ Object
Override in your resource to filter the creatable keys.
- .create(context) ⇒ Object
- .create_model ⇒ Object
- .default_attribute_options ⇒ Object
- .fields ⇒ Object
- .filter(attr, *args) ⇒ Object
- .filter_records(filters, options) ⇒ 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
- .find_count(filters, options = {}) ⇒ Object
- .has_many(*attrs) ⇒ Object
- .has_one(*attrs) ⇒ Object
- .inherited(base) ⇒ Object
- .is_filter_association?(filter) ⇒ Boolean
-
.method_missing(method, *args) ⇒ Object
TODO: remove this after the createable_fields and updateable_fields are phased out :nocov:.
- .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
- .sort_records(records, order_options) ⇒ Object
-
.sortable_fields(context = nil) ⇒ Object
Override in your resource to filter the sortable keys.
-
.updatable_fields(context = nil) ⇒ Object
Override in your resource to filter the updatable 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.
24 25 26 27 |
# File 'lib/jsonapi/resource.rb', line 24 def initialize(model, context = nil) @model = model @context = context end |
Class Attribute Details
._allowed_filters ⇒ Object
Returns the value of attribute _allowed_filters.
261 262 263 |
# File 'lib/jsonapi/resource.rb', line 261 def _allowed_filters @_allowed_filters end |
._associations ⇒ Object
Returns the value of attribute _associations.
261 262 263 |
# File 'lib/jsonapi/resource.rb', line 261 def _associations @_associations end |
._attributes ⇒ Object
Returns the value of attribute _attributes.
261 262 263 |
# File 'lib/jsonapi/resource.rb', line 261 def _attributes @_attributes end |
._paginator ⇒ Object
Returns the value of attribute _paginator.
261 262 263 |
# File 'lib/jsonapi/resource.rb', line 261 def _paginator @_paginator end |
._type ⇒ Object
Returns the value of attribute _type.
261 262 263 |
# File 'lib/jsonapi/resource.rb', line 261 def _type @_type end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
9 10 11 |
# File 'lib/jsonapi/resource.rb', line 9 def context @context end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
10 11 12 |
# File 'lib/jsonapi/resource.rb', line 10 def model @model end |
Class Method Details
._allowed_filter?(filter) ⇒ Boolean
575 576 577 |
# File 'lib/jsonapi/resource.rb', line 575 def _allowed_filter?(filter) !_allowed_filters[filter].nil? end |
._as_parent_key ⇒ Object
546 547 548 |
# File 'lib/jsonapi/resource.rb', line 546 def _as_parent_key @_as_parent_key ||= "#{_type.to_s.singularize}_#{_primary_key}" end |
._association(type) ⇒ Object
533 534 535 536 |
# File 'lib/jsonapi/resource.rb', line 533 def _association(type) type = type.to_sym @_associations[type] end |
._attribute_options(attr) ⇒ Object
quasi private class methods
520 521 522 |
# File 'lib/jsonapi/resource.rb', line 520 def (attr) .merge(@_attributes[attr]) end |
._has_association?(type) ⇒ Boolean
528 529 530 531 |
# File 'lib/jsonapi/resource.rb', line 528 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
571 572 573 |
# File 'lib/jsonapi/resource.rb', line 571 def _model_class @model ||= _model_name.to_s.safe_constantize end |
._model_name ⇒ Object
538 539 540 |
# File 'lib/jsonapi/resource.rb', line 538 def _model_name @_model_name ||= self.name.demodulize.sub(/Resource$/, '') end |
._primary_key ⇒ Object
542 543 544 |
# File 'lib/jsonapi/resource.rb', line 542 def _primary_key @_primary_key ||= :id end |
._resource_name_from_type(type) ⇒ Object
554 555 556 557 558 559 560 561 |
# File 'lib/jsonapi/resource.rb', line 554 def _resource_name_from_type(type) class_name = @@resource_types[type] if class_name.nil? class_name = "#{type.to_s.singularize}_resource".camelize @@resource_types[type] = class_name end return class_name end |
._updatable_associations ⇒ Object
524 525 526 |
# File 'lib/jsonapi/resource.rb', line 524 def _updatable_associations @_associations.map { |key, association| key } end |
.apply_filter(records, filter, value, options = {}) ⇒ Object
386 387 388 |
# File 'lib/jsonapi/resource.rb', line 386 def apply_filter(records, filter, value, = {}) records.where(filter => value) end |
.apply_filters(records, filters, options = {}) ⇒ Object
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
# File 'lib/jsonapi/resource.rb', line 390 def apply_filters(records, filters, = {}) required_includes = [] if filters 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 end if required_includes.any? records.includes(required_includes) elsif records.respond_to? :to_ary records else records.all end end |
.apply_includes(records, directives) ⇒ Object
366 367 368 369 |
# File 'lib/jsonapi/resource.rb', line 366 def apply_includes(records, directives) records = records.includes(*directives.model_includes) if directives records end |
.apply_pagination(records, paginator, order_options) ⇒ Object
371 372 373 374 375 376 |
# File 'lib/jsonapi/resource.rb', line 371 def apply_pagination(records, paginator, ) if paginator records = paginator.apply(records, ) end records end |
.apply_sort(records, order_options) ⇒ Object
378 379 380 381 382 383 384 |
# File 'lib/jsonapi/resource.rb', line 378 def apply_sort(records, ) if .any? records.order() else records end end |
.attribute(attr, options = {}) ⇒ Object
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/jsonapi/resource.rb', line 286 def attribute(attr, = {}) check_reserved_attribute_name(attr) if (attr.to_sym == :id) && ([:format].nil?) ActiveSupport::Deprecation.warn('Id without format is no longer supported. Please remove ids from attributes, or specify a format.') end @_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
280 281 282 283 284 |
# File 'lib/jsonapi/resource.rb', line 280 def attributes(*attrs) attrs.each do |attr| attribute(attr) end end |
.construct_order_options(sort_params) ⇒ Object
583 584 585 586 587 588 589 590 |
# File 'lib/jsonapi/resource.rb', line 583 def (sort_params) return {} unless sort_params sort_params.each_with_object({}) { |sort, order_hash| field = sort[:field] == 'id' ? _primary_key : sort[:field] order_hash[field] = sort[:direction] } end |
.creatable_fields(context = nil) ⇒ Object
Override in your resource to filter the creatable keys
353 354 355 |
# File 'lib/jsonapi/resource.rb', line 353 def creatable_fields(context = nil) _updatable_associations | _attributes.keys end |
.create(context) ⇒ Object
263 264 265 |
# File 'lib/jsonapi/resource.rb', line 263 def create(context) self.new(self.create_model, context) end |
.create_model ⇒ Object
267 268 269 |
# File 'lib/jsonapi/resource.rb', line 267 def create_model _model_class.new end |
.default_attribute_options ⇒ Object
304 305 306 |
# File 'lib/jsonapi/resource.rb', line 304 def {format: :default} end |
.fields ⇒ Object
362 363 364 |
# File 'lib/jsonapi/resource.rb', line 362 def fields _associations.keys | _attributes.keys end |
.filter(attr, *args) ⇒ Object
324 325 326 |
# File 'lib/jsonapi/resource.rb', line 324 def filter(attr, *args) @_allowed_filters[attr.to_sym] = args. end |
.filter_records(filters, options) ⇒ Object
417 418 419 420 421 422 423 |
# File 'lib/jsonapi/resource.rb', line 417 def filter_records(filters, ) include_directives = [:include_directives] records = records() records = apply_includes(records, include_directives) apply_filters(records, filters, ) end |
.filters(*attrs) ⇒ Object
320 321 322 |
# File 'lib/jsonapi/resource.rb', line 320 def filters(*attrs) @_allowed_filters.merge!(attrs.inject( Hash.new ) { |h, attr| h[attr] = {}; h }) end |
.find(filters, options = {}) ⇒ Object
Override this method if you have more complex requirements than this basic find method provides
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/jsonapi/resource.rb', line 434 def find(filters, = {}) context = [:context] records = filter_records(filters, ) sort_criteria = .fetch(:sort_criteria) { [] } = (sort_criteria) records = sort_records(records, ) records = apply_pagination(records, [:paginator], ) resources = [] records.each do |model| resources.push self.new(model, context) end return resources end |
.find_by_key(key, options = {}) ⇒ Object
453 454 455 456 457 458 459 460 461 462 463 |
# File 'lib/jsonapi/resource.rb', line 453 def find_by_key(key, = {}) context = [:context] include_directives = [:include_directives] records = records() records = apply_includes(records, include_directives) model = records.where({_primary_key => key}).first if model.nil? raise JSONAPI::Exceptions::RecordNotFound.new(key) end self.new(model, context) end |
.find_count(filters, options = {}) ⇒ Object
429 430 431 |
# File 'lib/jsonapi/resource.rb', line 429 def find_count(filters, = {}) filter_records(filters, ).count end |
.has_many(*attrs) ⇒ Object
312 313 314 |
# File 'lib/jsonapi/resource.rb', line 312 def has_many(*attrs) _associate(Association::HasMany, *attrs) end |
.has_one(*attrs) ⇒ Object
308 309 310 |
# File 'lib/jsonapi/resource.rb', line 308 def has_one(*attrs) _associate(Association::HasOne, *attrs) end |
.inherited(base) ⇒ Object
239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/jsonapi/resource.rb', line 239 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
480 481 482 |
# File 'lib/jsonapi/resource.rb', line 480 def is_filter_association?(filter) filter == _type || _associations.include?(filter) end |
.method_missing(method, *args) ⇒ Object
TODO: remove this after the createable_fields and updateable_fields are phased out :nocov:
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/jsonapi/resource.rb', line 334 def method_missing(method, *args) if method.to_s.match /createable_fields/ ActiveSupport::Deprecation.warn("`createable_fields` is deprecated, please use `creatable_fields` instead") self.creatable_fields(*args) elsif method.to_s.match /updateable_fields/ ActiveSupport::Deprecation.warn("`updateable_fields` is deprecated, please use `updatable_fields` instead") self.updatable_fields(*args) else super end end |
.model_name(model) ⇒ Object
316 317 318 |
# File 'lib/jsonapi/resource.rb', line 316 def model_name(model) @_model_name = model.to_sym end |
.module_path ⇒ Object
579 580 581 |
# File 'lib/jsonapi/resource.rb', line 579 def module_path @module_path ||= self.name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : '' end |
.paginator(paginator) ⇒ Object
567 568 569 |
# File 'lib/jsonapi/resource.rb', line 567 def paginator(paginator) @_paginator = paginator end |
.primary_key(key) ⇒ Object
328 329 330 |
# File 'lib/jsonapi/resource.rb', line 328 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)
467 468 469 |
# File 'lib/jsonapi/resource.rb', line 467 def records( = {}) _model_class end |
.resource_for(type) ⇒ Object
252 253 254 255 256 257 258 259 |
# File 'lib/jsonapi/resource.rb', line 252 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
271 272 273 |
# File 'lib/jsonapi/resource.rb', line 271 def () @_routing_resource_options = end |
.routing_resource_options ⇒ Object
275 276 277 |
# File 'lib/jsonapi/resource.rb', line 275 def @_routing_resource_options ||= {} end |
.sort_records(records, order_options) ⇒ Object
425 426 427 |
# File 'lib/jsonapi/resource.rb', line 425 def sort_records(records, ) apply_sort(records, ) end |
.sortable_fields(context = nil) ⇒ Object
Override in your resource to filter the sortable keys
358 359 360 |
# File 'lib/jsonapi/resource.rb', line 358 def sortable_fields(context = nil) _attributes.keys end |
.updatable_fields(context = nil) ⇒ Object
Override in your resource to filter the updatable keys
348 349 350 |
# File 'lib/jsonapi/resource.rb', line 348 def updatable_fields(context = nil) _updatable_associations | _attributes.keys - [:id] 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
515 516 517 |
# File 'lib/jsonapi/resource.rb', line 515 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
510 511 512 |
# File 'lib/jsonapi/resource.rb', line 510 def verify_custom_filter(filter, value, context = nil) return filter, value end |
.verify_filter(filter, raw, context = nil) ⇒ Object
484 485 486 487 488 489 490 491 492 493 |
# File 'lib/jsonapi/resource.rb', line 484 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
471 472 473 474 475 476 477 478 |
# File 'lib/jsonapi/resource.rb', line 471 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
496 497 498 499 500 |
# File 'lib/jsonapi/resource.rb', line 496 def verify_key(key, context = nil) key && Integer(key) rescue raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key) end |
.verify_keys(keys, context = nil) ⇒ Object
override to allow for key processing and checking
503 504 505 506 507 |
# File 'lib/jsonapi/resource.rb', line 503 def verify_keys(keys, context = nil) return keys.collect do |key| verify_key(key, context) end end |
Instance Method Details
#change(callback) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/jsonapi/resource.rb', line 37 def change(callback) completed = false if @changing run_callbacks callback do completed = (yield == :completed) end else run_callbacks is_new? ? :create : :update do @changing = true run_callbacks callback do completed = (yield == :completed) end if @save_needed || is_new? completed = (save == :completed) end end end return completed ? :completed : :accepted end |
#create_has_many_links(association_type, association_key_values) ⇒ Object
66 67 68 69 70 |
# File 'lib/jsonapi/resource.rb', line 66 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
103 104 105 |
# File 'lib/jsonapi/resource.rb', line 103 def fetchable_fields self.class.fields end |
#id ⇒ Object
29 30 31 |
# File 'lib/jsonapi/resource.rb', line 29 def id model.send(self.class._primary_key) end |
#is_new? ⇒ Boolean
33 34 35 |
# File 'lib/jsonapi/resource.rb', line 33 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 authorization.
109 110 111 |
# File 'lib/jsonapi/resource.rb', line 109 def records_for(association_name, = {}) model.send association_name end |
#remove ⇒ Object
60 61 62 63 64 |
# File 'lib/jsonapi/resource.rb', line 60 def remove run_callbacks :remove do _remove end end |
#remove_has_many_link(association_type, key) ⇒ Object
84 85 86 87 88 |
# File 'lib/jsonapi/resource.rb', line 84 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
90 91 92 93 94 |
# File 'lib/jsonapi/resource.rb', line 90 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
96 97 98 99 100 |
# File 'lib/jsonapi/resource.rb', line 96 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
72 73 74 75 76 |
# File 'lib/jsonapi/resource.rb', line 72 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
78 79 80 81 82 |
# File 'lib/jsonapi/resource.rb', line 78 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 |