lib/ams_lazy_relationships/core/relationship_wrapper_methods.rb
# frozen_string_literal: true
module AmsLazyRelationships::Core
# Defines convenience methods - wraps `has_many/belongs_to/has_one` and defines a
# lazy_has_many, lazy_has_one and lazy_belongs_to.
#
# Calling lazy_has_one in your serializer class will:
# - define a lazy_relationship
# - define a has_one relationship
#
# You can optionally pass a block, just like in standard AMS relationships
# If block is not present it'll call `lazy_xxx` method where `xxx` is the
# name of the relationship.
module RelationshipWrapperMethods
private
def define_relationship_wrapper_methods
%i[has_many belongs_to has_one].each do |relationship_type|
define_singleton_method(
"lazy_#{relationship_type}"
) do |relationship_name, options = {}, &block|
define_lazy_association(relationship_type, relationship_name, options, block)
end
end
end
def define_lazy_association(type, name, options, block)
lazy_relationship_option_keys = %i[load_for loader]
real_relationship_options = options.except(*lazy_relationship_option_keys)
public_send(type, name.to_sym, real_relationship_options) do |serializer|
block_value = instance_exec(serializer, &block) if block
if block && block_value != :nil
# respect the custom finder for lazy association
# @see https://github.com/rails-api/active_model_serializers/blob/v0.10.10/lib/active_model/serializer/reflection.rb#L165-L168
block_value
else
# provide default lazy association finder in a form of lambda,
# in order to play nice with possible `include_data` setting.
# @see lib/ams_lazy_relationships/extensions/reflection.rb
serializer.method("lazy_#{name}")
end
end
lazy_relationship(name, **options.slice(*lazy_relationship_option_keys))
end
end
end