-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature Request] Support for nested associations defined at callsite #409
Comments
I think the increased ability to customize serializers would make this easier. See this issue, on extractor configurability: #404 That said, it's already possible today, with some hacking around. This is a dump of some experimentation I did earlier, where the You should be able to take the code below and make some modifications to it, to get what you're asking for today. # Invoke with this:
# InputBlueprint.render({ :user => User.all.first }, selected_keys: ['user.first_name', 'user.groups.name'], :cache => {})
# Example output:
# "{\"private\":{\"exchange_rates\":{}},\"user\":{\"first_name\":\"Master\",\"groups\":[{\"name\":\"Kontroll\"}]}}"
def explode_string(str)
parts = str.split('.')
parts.map.with_index { |_, index| parts[0..index].join('.') }
end
Blueprinter.configure do |config|
config.if = ->(field_name, obj, options) {
# puts "global-if for field #{field_name}"
# puts "global-if: #{options}"
if stack = options[:stack]
stack_key = stack.join('.')
full_key = "#{stack_key}.#{field_name}"
if selected_keys = options[:selected_keys]
# the only keys that may be relevant, are those that start with the current stack
relevant_keys = selected_keys.find_all { |key| key.start_with?(stack_key) }
exploded_keys = relevant_keys.flat_map { |key| explode_string(key) }
exploded_keys.include?(full_key)
else # no selected keys, include all of them
# puts "no selected keys"
true
end
else # no stack exist (root node)
# puts "no stack"
true
end
}
end
class MyAssociationExtractor < Blueprinter::AssociationExtractor
def extract(association_name, object, local_options, options = {})
# puts "AssociationExtractor #{association_name} local_options: #{local_options}"
# puts "AssociationExtractor #{association_name} options: #{options}"
local_options[:stack] = [] unless local_options[:stack]
local_options[:stack] << association_name.to_s
super
ensure
local_options[:stack].pop
end
end
class CacheExtractor < Blueprinter::Extractor
def extract(field_name, object, local_options, options = {})
# puts "local_options: #{local_options}"
# puts "options: #{options}"
local_options[:mut] = 1
options[:mut] = 2
if cache = local_options[:cache]
object_cache_key = object.id.to_s
if cache.key?(object_cache_key)
if cache[object_cache_key].key?(field_name)
puts 'cache hit!' # FIXME remove
return cache[object_cache_key][field_name] # cache hit
end
else
puts 'cache miss!'
cache[object_cache_key] = {}
end
val = object.send(field_name) # cache miss
cache[object_cache_key][field_name] = val
val
else
puts 'no cache!'
object.send(field_name)
# super # see if this works
end
end
end
class GroupBlueprint < Blueprinter::Base
identifier :id
fields :name
fields :internal_identifier
end
class UserBlueprint < Blueprinter::Base
identifier :id
fields :first_name, :last_name
field :primary_email, extractor: CacheExtractor, made_up_option: 'hello_from_field_option'
field :roles, extractor: CacheExtractor
association :groups, blueprint: GroupBlueprint, extractor: MyAssociationExtractor
end
class InputBlueprint < Blueprinter::Base
# identifier :id
association :user, blueprint: UserBlueprint, extractor: MyAssociationExtractor
field :private do |input, options|
{
:exchange_rates => {}, # input.active_expenses…
}
end
end |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Sorry for the late reply, thanks for that example @sandstrom ! |
Is there an existing issue for this?
Is your feature request related to a problem? Please describe
ActiveRecord lets you preload nested associations e.g.:
I would like something similar with blueprinter, where by default associations are not included in the result, unless specified at the callsite.
Is this already possible, and if so, how might I go about doing it?
Describe the feature you'd like to see implemented
I want to be able to do something like this:
In order to do this, I suspect I need some ability to take the options hash and go one level deeper each time we traverse an association, so that if I'm in the BarBlueprint, the options hash becomes
{ associations: [:baz, bez] }
. But to my knowledge the options hash stays the same no matter how nested the blueprint is.Thanks!
Describe alternatives you've considered
No response
Additional context
No response
The text was updated successfully, but these errors were encountered: