To kick off 1.0 development, this PR overhauls sideloading. It is focused on
reads-only, and does not account for polymorphic relationships. Additional development will continue in the 1.0.0-dev branch.
We previously allowed a nested syntax like this:
allow_sideload :foo do
allow_sideload :bar do
allow_sideload :baz
end
end
This is a holdover from before Resources were introduced. It caused code
complexity because the allow_sideload logic needed to live on both
Resource and Sideload. The logic Resources need for sideloading is now
defined in a mixin - resource/sideloading.rb and this type of nesting is
no longer supported.
This opens the door for more a more well-defined Sideload interface.
allow_sideload now (optionally) accepts a Sideload class, instead of
defining everything in-line. This also allows has_many-type macros
out-of-the-box, even for POROs. The only thing needed is a scope proc.
The ActiveRecord adapter now implements this new interface, simplifying
the adapter and removing the need for sideloading_module. It also uses
the interface to derive the various options, meaning we can now use
one-liners to define associations.
This is all best illustrated in code:
# PORO
has_many :comments do
scope do |posts|
# ... code ...
end
end
# via Sideload class
has_many :comments, class: CommentSideload
# See sideload/*.rb and ActiveRecord adapter for examples
class CommentSideload < JsonapiCompliable::Sideload::HasMany
def scope(parents)
base_scope.where(post_id: parents.map(&:id))
end
def assign_each(post, comments)
# custom logic
end
end
# you can still pass a block even when using a class
# ( block code "wins" )
has_many :comments, class: CommentSideload do
assign do |posts, comments|
# ... code ...
end
end
# Options are still accepted
has_many :comments,
resource: CommentResource,
base_scope: -> { Comment.all },
foreign_key: :post_id
# assign still exists, but the more-common assign_each
# now also exists with a simpler interface
# (this will probably be renamed in a future commit)
has_many :comments do
assign_each do |post, comments|
comments.select { |c| c.post_id == post.id }
end
end
# if using ActiveRecord
has_many :comments
belongs_to :post
has_one :bio
many_to_many :teams
I have purposefully not made all tests pass as I am saving for future
refactors. The tests passing here are:
spec/integration/rails/finders_spec.rb
spec/integration/rails/sideload_whitelist_spec.rb
spec/sideloading_spec.rb
spec/sideload_spec.rb
spec/sideload/*.rb
In addition, I removed YARD docs every time I touched a method. The thought
being a separate docs-only commit will come in the future, but for now comments
just add a lot of noise.
Other notables:
spec/fixtures/poro.rb introduced for testing POROs with an in-memory
database. Will be moving all non-integration specs to this.
:scope option renamed to :base_scope
:has_and_belongs_to_many renamed to :many_to_many
We now raise helpful error if trying to paginate a relationship from index
The main interface is sideload.rb, see subclasses for each type of
relationship in sideload/*.rb
Default sort still exists, but the "default default sort" is nothing (it was)
previously [{ id: :asc }] and is now []
Instead of sideloading_module, adapters now need to define a mapping of
sideload classes:
@wadetandy sorry for the bomb of a commit but this really shook up the fundamentals and I wanted to make sure the interface would still support all these associations (polymorphic-aside).
To kick off 1.0 development, this PR overhauls sideloading. It is focused on reads-only, and does not account for polymorphic relationships. Additional development will continue in the
1.0.0-dev
branch.We previously allowed a nested syntax like this:
This is a holdover from before Resources were introduced. It caused code complexity because the
allow_sideload
logic needed to live on both Resource and Sideload. The logic Resources need for sideloading is now defined in a mixin -resource/sideloading.rb
and this type of nesting is no longer supported.This opens the door for more a more well-defined Sideload interface.
allow_sideload
now (optionally) accepts a Sideload class, instead of defining everything in-line. This also allowshas_many
-type macros out-of-the-box, even for POROs. The only thing needed is ascope
proc.The
ActiveRecord
adapter now implements this new interface, simplifying the adapter and removing the need forsideloading_module
. It also uses the interface to derive the various options, meaning we can now use one-liners to define associations.This is all best illustrated in code:
I have purposefully not made all tests pass as I am saving for future refactors. The tests passing here are:
spec/integration/rails/finders_spec.rb
spec/integration/rails/sideload_whitelist_spec.rb
spec/sideloading_spec.rb
spec/sideload_spec.rb
spec/sideload/*.rb
In addition, I removed YARD docs every time I touched a method. The thought being a separate docs-only commit will come in the future, but for now comments just add a lot of noise.
Other notables:
spec/fixtures/poro.rb
introduced for testing POROs with an in-memory database. Will be moving all non-integration specs to this.:scope
option renamed to:base_scope
:has_and_belongs_to_many
renamed to:many_to_many
index
sideload.rb
, see subclasses for each type of relationship insideload/*.rb
[{ id: :asc }]
and is now[]
Instead of
sideloading_module
, adapters now need to define a mapping of sideload classes: