jb
jb copied to clipboard
TypeError when rendering a partial directly
class TeasController < ApplicationController
def create
result = NewTeaService.new.call(params.to_unsafe_h)
case result
in Success[:created, Tea => tea]
render tea, status: :created
in Failure[_, errors]
render json: errors, status: :unprocessable_entity
end
end
end
This action tries to render app/views/teas/_tea.json.jbuilder
# app/views/teas/_tea.json.jbuilder
tea.slice(*%i[
id
name
country
created_at
updated_at
])
but fails with
TypeError (no implicit conversion of Array into String):
rack (2.2.3) lib/rack/etag.rb:69:in `<<'
rack (2.2.3) lib/rack/etag.rb:69:in `block in digest_body'
actionpack (6.1.4.1) lib/action_dispatch/http/response.rb:158:in `each'
actionpack (6.1.4.1) lib/action_dispatch/http/response.rb:158:in `each_chunk'
actionpack (6.1.4.1) lib/action_dispatch/http/response.rb:140:in `each'
actionpack (6.1.4.1) lib/action_dispatch/http/response.rb:76:in `each'
actionpack (6.1.4.1) lib/action_dispatch/http/response.rb:493:in `each'
rack (2.2.3) lib/rack/etag.rb:67:in `digest_body'
rack (2.2.3) lib/rack/etag.rb:31:in `call'
rack (2.2.3) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.3) lib/rack/head.rb:12:in `call'
activerecord (6.1.4.1) lib/active_record/migration.rb:601:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.1.4.1) lib/active_support/callbacks.rb:98:in `run_callbacks'
actionpack (6.1.4.1) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/actionable_exceptions.rb:18:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.1.4.1) lib/rails/rack/logger.rb:37:in `call_app'
railties (6.1.4.1) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.1.4.1) lib/active_support/tagged_logging.rb:99:in `block in tagged'
activesupport (6.1.4.1) lib/active_support/tagged_logging.rb:37:in `tagged'
activesupport (6.1.4.1) lib/active_support/tagged_logging.rb:99:in `tagged'
railties (6.1.4.1) lib/rails/rack/logger.rb:26:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.3) lib/rack/runtime.rb:22:in `call'
activesupport (6.1.4.1) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/static.rb:24:in `call'
rack (2.2.3) lib/rack/sendfile.rb:110:in `call'
actionpack (6.1.4.1) lib/action_dispatch/middleware/host_authorization.rb:98:in `call'
railties (6.1.4.1) lib/rails/engine.rb:539:in `call'
puma (5.5.0) lib/puma/configuration.rb:249:in `call'
puma (5.5.0) lib/puma/request.rb:77:in `block in handle_request'
puma (5.5.0) lib/puma/thread_pool.rb:340:in `with_force_shutdown'
puma (5.5.0) lib/puma/request.rb:76:in `handle_request'
puma (5.5.0) lib/puma/server.rb:447:in `process_client'
puma (5.5.0) lib/puma/thread_pool.rb:147:in `block in spawn_thread'
unless I append .to_json
to the partial. Is this working as intended?
I'm getting same error when I use this:
ApplicationController.renderer.render(
partial: 'shared/item',
locals: { item: item }
)
and my file is /view/shared/_item.json.jb
Only tested this for the simple ApplicationController.render(partial: ...
case on Rails 7.0.4, but in case anyone else finds themselves here this patch seems to get it working:
module Jb
module PartialRenderer
module JSONizer
def render_partial_template(*)
rendered_template = super
rendered_template.instance_variable_set :@body, rendered_template.body.to_json if rendered_template.template.respond_to?(:handler) && (rendered_template.template.handler == Jb::Handler)
rendered_template
end
end
end
end
::ActionView::PartialRenderer.prepend ::Jb::PartialRenderer::JSONizer
The underlying issue is that jb
patches ActionView::TemplateRenderer
, but when you call ApplicationController.render(partial: ...)
it uses ActionView::PartialRenderer
.
Note however that with this patch, calls to render(partial: ...
within another view/partial will now also return JSON, which could mess things up with nested partials. Not sure of a good workaround yet other than using JSON.parse
inside the views.