I thought I could use Jbuilder outside of Rails controllers. The documentation said so.
I wrote this module, to include into a service object. Which is integrated in a Rails 6 api app, but is not inheriting from ActiveRecord.
module JsonGenerator
def to_json
template = File.read("#{::Rails.root}/path/to/template.json.jbuilder")
Jbuilder.new { |json| eval template }.target!
end
end
class Converter::Album
include JsonGenerator
end
This is working if I don't use any partial. But when I do, using a syntax like this:
json.artists artists do |artist|
json.partial! 'artist', artist: artist
end
I get this error :
Failure/Error: eval template
TypeError:
{:artist=>#<Converter::Artist:0x00007fd0d1a99dc8 @name="Bob">} is not a symbol nor a string
The problem seems to be that Jbuilder partials can't accept PORO as argument ?
I don't want to use eval
anyway, but it's the only way I found for loading a template which is not in the views
folder.
If I copy paste all my template directly as an argument to the Jbuilder.new
method, I get the same error.
Update 04/12/2019
I tried this line
json.partial! partial: 'artist', locals: { artist: artist }
and even though it loads the partial, the data it generates is wrong.
I get this
"artists" => [{"partial!"=>{"locals"=>{"name"=>"Bob", "instrument"=>"piano"}, "partial"=>"artist"}}]
instead of
"artists" => [{"name"=>"Bob", "instrument"=>"piano"}]
For whatever reason it seems like you have to explicitely name the args when outside rails magic:
json.partial! partial: 'artist', locals: { artist: artist }
To avoid the eval, I would try something with the rendered (untested):
def to_json
ApplicationController.render(template: 'albums/show.json.jbuilder', assigns: { album: self }, formats: [:json], handlers: [:builder])
end
Or with the new renderer:
def to_json
renderer = ApplicationController.new
renderer.render('albums/show.json.jbuilder', locals: { album: self }, formats: [:json], handlers: [:builder])
end
I thought I could use Jbuilder outside of Rails controllers. The documentation said so.
You can, but not all of the methods you can use within the view context are available. This is because they are actually two different objects, Jbuilder and JbuilderTemplate , the latter of which accepts a context
argument, which is an instance of ActionView::Base
(or subclass thereof).
The object you're using outside of the view context is an instance of Jbuilder
and doesn't have the #partial!
method, which is why you have the "partial!"
key in the returned JSON -- it's not treated any differently than any other key.
As far as I know, the only (easy) way to accomplish what you want to do is to use ActionController::Renderer (as @Mene said).
ApplicationController.render 'path/to/template.jbuilder', locals: {...}, assigns: {...}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.