Using implicit default view with config.sort_fields_by = :definition leads to SystemStackError
colszowka opened this issue · comments
- I guess this is related to #197
- I tested this on currently latest blueprinter 0.25.2 and Ruby 2.7.2
Background: We'd like to gradually move to using views on some of our blueprints that have naturally grown to be fairly complex, and need the fields in the output to be sorted by definition order
As we have realized blueprinter has an implicit view :default
that could be used to basically convert from the top-level fields into views using view :default
and include_views
in there, so we don't have to adjust any calling code to pass an explicit diffferent view.
However, when config.sort_fields_by = :definition
is set this leads to a stack level to deep
exception. Here's a simple example:
require "json"
require "blueprinter"
require "pp"
require "ostruct"
Blueprinter.configure do |config|
config.sort_fields_by = :definition
end
record = OpenStruct.new id: 123, name: "foo", address: "bar"
class MyBlueprint < Blueprinter::Base
identifier :id
view :detailed do
field :address
end
view :full do
include_view :detailed
field :name
end
view :default do
include_view :detailed
field :name
end
end
pp MyBlueprint.render_as_hash(record, view: :full)
# => {:id=>123, :address=>"bar", :name=>"foo"}
pp MyBlueprint.render_as_hash(record)
# => stack level too deep (SystemStackError)
Passing view: default
explicitly in the second example leads to the same problem unfortunately. Without the sort_fields_by
config change it works as expected
Thanks for reporting this @colszowka!
@mcclayton Thanks for this great library :)
For what it's worth, I'm not sure this really is a bug in blueprinter since using the default view like this is not even on the documentation so this is mostly me trying to stretch things a bit in order to avoid having to pass the view explicitly in existing code, so maybe this should actually be closed.
We were able to work around the problem we were facing by adding this override on our ApplicationBlueprint
:
def self.prepare(object, view_name:, **rest)
view_name = :standard if view_name == :default && view_collection.has_view?(:standard)
super object, view_name: view_name, **rest
end
Now we can do view :standard
and basically achieve what I outlined above, and otherwise the internal default view works as usual so it fixes our problem here
That makes sense @colszowka, glad you got a workaround figured out. I think the larger thing this brings up is the lack of documentation for the implicitly defined :default
view and for the core maintainers team to think through how it should behave in edge cases like this. Thanks again for bringing it to our attention.
Closing this issue, creating a documentation task #264