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
576 577 578 |
# File 'lib/jsonapi/resource.rb', line 576 def _allowed_filter?(filter) !_allowed_filters[filter].nil? end |
._as_parent_key ⇒ Object
547 548 549 |
# File 'lib/jsonapi/resource.rb', line 547 def _as_parent_key @_as_parent_key ||= "#{_type.to_s.singularize}_#{_primary_key}" end |
._association(type) ⇒ Object
534 535 536 537 |
# File 'lib/jsonapi/resource.rb', line 534 def _association(type) type = type.to_sym @_associations[type] end |
._attribute_options(attr) ⇒ Object
quasi private class methods
521 522 523 |
# File 'lib/jsonapi/resource.rb', line 521 def (attr) .merge(@_attributes[attr]) end |
._has_association?(type) ⇒ Boolean
529 530 531 532 |
# File 'lib/jsonapi/resource.rb', line 529 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
572 573 574 |
# File 'lib/jsonapi/resource.rb', line 572 def _model_class @model ||= _model_name.to_s.safe_constantize end |
._model_name ⇒ Object
539 540 541 |
# File 'lib/jsonapi/resource.rb', line 539 def _model_name @_model_name ||= self.name.demodulize.sub(/Resource$/, '') end |
._primary_key ⇒ Object
543 544 545 |
# File 'lib/jsonapi/resource.rb', line 543 def _primary_key @_primary_key ||= :id end |
._resource_name_from_type(type) ⇒ Object
555 556 557 558 559 560 561 562 |
# File 'lib/jsonapi/resource.rb', line 555 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
525 526 527 |
# File 'lib/jsonapi/resource.rb', line 525 def _updatable_associations @_associations.map { |key, association| key } end |
.apply_filter(records, filter, value, options = {}) ⇒ Object
387 388 389 |
# File 'lib/jsonapi/resource.rb', line 387 def apply_filter(records, filter, value, = {}) records.where(filter => value) end |
.apply_filters(records, filters, options = {}) ⇒ Object
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 416 |
# File 'lib/jsonapi/resource.rb', line 391 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
367 368 369 370 |
# File 'lib/jsonapi/resource.rb', line 367 def apply_includes(records, directives) records = records.includes(*directives.model_includes) if directives records end |
.apply_pagination(records, paginator, order_options) ⇒ Object
372 373 374 375 376 377 |
# File 'lib/jsonapi/resource.rb', line 372 def apply_pagination(records, paginator, ) if paginator records = paginator.apply(records, ) end records end |
.apply_sort(records, order_options) ⇒ Object
379 380 381 382 383 384 385 |
# File 'lib/jsonapi/resource.rb', line 379 def apply_sort(records, ) if .any? records.order() else records end end |
.attribute(attr, options = {}) ⇒ Object
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/jsonapi/resource.rb', line 287 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 285 |
# File 'lib/jsonapi/resource.rb', line 280 def attributes(*attrs) = attrs..dup attrs.each do |attr| attribute(attr, ) end end |
.construct_order_options(sort_params) ⇒ Object
584 585 586 587 588 589 590 591 |
# File 'lib/jsonapi/resource.rb', line 584 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
354 355 356 |
# File 'lib/jsonapi/resource.rb', line 354 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
305 306 307 |
# File 'lib/jsonapi/resource.rb', line 305 def {format: :default} end |
.fields ⇒ Object
363 364 365 |
# File 'lib/jsonapi/resource.rb', line 363 def fields _associations.keys | _attributes.keys end |
.filter(attr, *args) ⇒ Object
325 326 327 |
# File 'lib/jsonapi/resource.rb', line 325 def filter(attr, *args) @_allowed_filters[attr.to_sym] = args. end |
.filter_records(filters, options) ⇒ Object
418 419 420 421 422 423 424 |
# File 'lib/jsonapi/resource.rb', line 418 def filter_records(filters, ) include_directives = [:include_directives] records = records() records = apply_includes(records, include_directives) apply_filters(records, filters, ) end |
.filters(*attrs) ⇒ Object
321 322 323 |
# File 'lib/jsonapi/resource.rb', line 321 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
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/jsonapi/resource.rb', line 435 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
454 455 456 457 458 459 460 461 462 463 464 |
# File 'lib/jsonapi/resource.rb', line 454 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
430 431 432 |
# File 'lib/jsonapi/resource.rb', line 430 def find_count(filters, = {}) filter_records(filters, ).count end |
.has_many(*attrs) ⇒ Object
313 314 315 |
# File 'lib/jsonapi/resource.rb', line 313 def has_many(*attrs) _associate(Association::HasMany, *attrs) end |
.has_one(*attrs) ⇒ Object
309 310 311 |
# File 'lib/jsonapi/resource.rb', line 309 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
481 482 483 |
# File 'lib/jsonapi/resource.rb', line 481 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:
335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/jsonapi/resource.rb', line 335 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
317 318 319 |
# File 'lib/jsonapi/resource.rb', line 317 def model_name(model) @_model_name = model.to_sym end |
.module_path ⇒ Object
580 581 582 |
# File 'lib/jsonapi/resource.rb', line 580 def module_path @module_path ||= self.name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : '' end |
.paginator(paginator) ⇒ Object
568 569 570 |
# File 'lib/jsonapi/resource.rb', line 568 def paginator(paginator) @_paginator = paginator end |
.primary_key(key) ⇒ Object
329 330 331 |
# File 'lib/jsonapi/resource.rb', line 329 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)
468 469 470 |
# File 'lib/jsonapi/resource.rb', line 468 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
426 427 428 |
# File 'lib/jsonapi/resource.rb', line 426 def sort_records(records, ) apply_sort(records, ) end |
.sortable_fields(context = nil) ⇒ Object
Override in your resource to filter the sortable keys
359 360 361 |
# File 'lib/jsonapi/resource.rb', line 359 def sortable_fields(context = nil) _attributes.keys end |
.updatable_fields(context = nil) ⇒ Object
Override in your resource to filter the updatable keys
349 350 351 |
# File 'lib/jsonapi/resource.rb', line 349 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
516 517 518 |
# File 'lib/jsonapi/resource.rb', line 516 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
511 512 513 |
# File 'lib/jsonapi/resource.rb', line 511 def verify_custom_filter(filter, value, context = nil) return filter, value end |
.verify_filter(filter, raw, context = nil) ⇒ Object
485 486 487 488 489 490 491 492 493 494 |
# File 'lib/jsonapi/resource.rb', line 485 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
472 473 474 475 476 477 478 479 |
# File 'lib/jsonapi/resource.rb', line 472 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
497 498 499 500 501 |
# File 'lib/jsonapi/resource.rb', line 497 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
504 505 506 507 508 |
# File 'lib/jsonapi/resource.rb', line 504 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 |