class EmployeeResource < ApplicationResource
# basic
attribute :first_name, :string
# is the same as
attribute :first_name, :string,
readable: true, writable: true, sortable: true, filterable: true
# writable and filterable can be required
attribute :first_name, :string, filterable: :required
# All of them accept a method name (of the resource)
attribute :first_name, :string, filterable: :admin?
# creates a read-only (by default) extra attribute
extra_attribute :salary
# defaults can be modified in your ApplicationResource
self.attributes_readable_by_default = false
self.attributes_writable_by_default = false
self.attributes_sortable_by_default = false
self.attributes_filterable_by_default = false
# pass a block for serialization
attribute :first_name, :string do
@object.first_name.upcase
end
# you can still have a separate serializer when logic gets heavy
# this would ONLY need customizations, not the full attribute list
self.serializer = EmployeeSerializer
# override sort logic
sort :title do |scope, dir|
scope.joins(:position).order("positions.title #{dir}")
end
# override filter logic
filter :title do |scope, value|
scope.joins(:position).where(positions: { title: value })
end
# relationships get readable/writable too
has_many :positions, readable: false
# you can modify the scoping however you'd like
def around_scoping(scope, query_hash)
if query_hash[:extra_fields][type].include?(:salary)
scope = scope.includes(:salary_info)
end
yield scope
end
end
Serializers are now optional, strong resources and spec payloads will be
removed in subsequent commits.
To get a further idea, spec/resource_spec.rb and
spec/serialization_spec.rb are good examples in addition to
spec/fixtures/legacy.rb.
To accomplish this:
Serialization monkey patches in jsonapi_compliable.rb. This library
derives the serializer from the model klass name, we need to derive it
from the resource. scope.rb sets a magic variable on the results, and
we get the class from that variable. Not only does this allow for
multiple resources with the same model, it ensures we never conflict
with inheritance, because all resources create a new serializer
subclass.
The logic in configuration.rb accounts for various subclassing
logic to work with anonymous/overridable/inferred serializers.
ApplicationResource now needs self.abstract_class = true just like
AR.
The old sort proc is still possible but is now sort_all. sort is
attribute-level.
Spec refactoring: things are now so simplified it's much easiest to
modify the resource at per-test runtime, as opposed to one common setup.
The premise of "auto-scoping" (ie render_jsonapi(Post.all)) is gone
and no longer relevant.
The EmployeeResource.all(params) interface you see in the controller
is nothing more than a simple wrapping around the Runner interface
introduced earlier. There's further testing/clean-up to do here; it
honestly shouldn't be part of this commit but got carried away.
Some comments and junk I'm leaving for now
Other:
We'll raise an appropriate error if you try to customize a filter/sort
an attribute that doesn't exist, if the request tries to filter/sort
on an attribute that doesn't exist or if it exists but doesn't support
the functionality or ig the guard fails.
The type currently does nothing. Next step is to integrate dry-types
for coercing query params and validating payloads.
This introduces a resource-level attributes API:
Serializers are now optional, strong resources and spec payloads will be removed in subsequent commits.
To get a further idea,
spec/resource_spec.rb
andspec/serialization_spec.rb
are good examples in addition tospec/fixtures/legacy.rb
.To accomplish this:
jsonapi_compliable.rb
. This library derives the serializer from the model klass name, we need to derive it from the resource.scope.rb
sets a magic variable on the results, and we get the class from that variable. Not only does this allow for multiple resources with the same model, it ensures we never conflict with inheritance, because all resources create a new serializer subclass.configuration.rb
accounts for various subclassing logic to work with anonymous/overridable/inferred serializers.ApplicationResource
now needsself.abstract_class = true
just like AR.sort
proc is still possible but is nowsort_all
.sort
is attribute-level.render_jsonapi(Post.all)
) is gone and no longer relevant.EmployeeResource.all(params)
interface you see in the controller is nothing more than a simple wrapping around theRunner
interface introduced earlier. There's further testing/clean-up to do here; it honestly shouldn't be part of this commit but got carried away.Other:
dry-types
for coercing query params and validating payloads.with_context
now has namespace as optional arg