ruby on rails - serializadores - ¿Cómo podría representar en una cadena una representación JSON de una vista JBuilder?
serializadores rails (8)
Estoy usando JBuilder para devolver algunos JSON. Tengo un index.json.jbuilder
que genera los datos y necesito convertirlos en una cadena. Sin embargo, no estoy seguro de cómo hacerlo, ya que @my_object.to_json
y @my_object.as_json
no pasan por JBuilder.
¿Cómo podría representar la vista de JBuilder como una cadena?
Desde la consola:
view = ApplicationController.view_context_class.new("#{Rails.root}/app/views")
JbuilderTemplate.encode(view){|json| json.partial!(''path/to/index'', @my_object) }
a través de https://github.com/rails/jbuilder/issues/84#issuecomment-38109709
En el controlador puedes hacer esto
def index
json = JbuilderTemplate.new(view_context) do |json|
json.partial! ''index''
end.attributes!
do_something(json)
render json: json
end
tenga en cuenta que necesita "_index.json.jbuilder" porque llama al renderizador parcial
Estoy renderizando una colección de usuarios como una cadena json en el controlador, de esta manera:
#controllers/users_controller.rb
def index
@users = User.all
@users_json = render_to_string( template: ''users.json.jbuilder'', locals: { users: @users})
end
#views/users/users.json.jbuilder
json.array!(users) do |json, user|
json.(user, :id, :name)
end
Mirando el código fuente, parece que puedes hacer:
json_string = Jbuilder.encode do |json|
json.partial! ''path/to/index'', @my_object
end
Si está haciendo esto en el controlador, una opción mucho más simple es intentar mover el código a la vista que está representando el controlador.
Describí esto aquí: https://github.com/shakacode/react-webpack-rails-tutorial#jbuilder-notes
Básicamente puedes llamar a render
en la vista, y listo. Me gusta esto:
<%= react_component(''App'', render(template: "/comments/index.json.jbuilder"),
generator_function: true, prerender: true) %>
Aquí están las notas sobre lo que sucede si desea pasar los datos del controlador a la vista:
class PagesController < ApplicationController
def index
@comments = Comment.all
# NOTE: The below notes apply if you want to set the value of the props in the controller, as
# compared to he view. However, it''s more convenient to use Jbuilder from the view. See
# app/views/pages/index.html.erb:20
#
# <%= react_component(''App'', render(template: "/comments/index.json.jbuilder"),
# generator_function: true, prerender: true) %>
#
#
# NOTE: this could be an alternate syntax if you wanted to pass comments as a variable to a partial
# @comments_json_sting = render_to_string(partial: "/comments/comments.json.jbuilder",
# locals: { comments: Comment.all }, format: :json)
# NOTE: @comments is used by the render_to_string call
# @comments_json_string = render_to_string("/comments/index.json.jbuilder")
# NOTE: It''s CRITICAL to call respond_to after calling render_to_string, or else Rails will
# not render the HTML version of the index page properly. (not a problem if you do this in the view)
# respond_to do |format|
# format.html
# end
end
end
Si la vista users.json.jbuilder
encuentra en la ruta predeterminada en relación con el controlador y no puede encontrar la plantilla, puede deberse a una discrepancia de format
, ya que puede estar intentando buscar el archivo de formato html
. Hay dos formas de solucionar esto:
Tener al cliente GET
/users/index.json
o
Especifique la opción de
formats
al llamar arender_to_string
(también se aplica arender
):
#controllers/users_controller.rb
def index
@users = User.all
@users_json = render_to_string( formats: ''json'' ) # Yes formats is plural
end
Esto ha sido verificado en Rails 4.1.
Siguiendo la punta de justingordon.
Si está utilizando un componente React, puede hacer lo siguiente.
En su controlador:
@users = User.all
En su opinión:
<%= react_component("YourComponentName",
props: render(''your_template.json.jbuilder'')) %>
Esto fue probado en Rails 5.1.
También puedes hacerlo de esta manera, lo que deja tu controlador un poco más limpio.
# controller
def new
@data = Data.all
end
# view
<% content_for :head do %>
<script type="text/javascript">
var mydata = <%= raw render :partial => ''path/to/partial'', :locals => {data: @data} %>;
</script>
<% end %>
# path/to/_partial.html.jbuilder
json.array!(@data) do |d|
json.extract! field1, :field2, :field3, :field4
json.url data_url(d, format: :json)
end
# layouts/application.html
<!DOCTYPE html>
<html>
<head>
<%= yield :head %>
</head>
<body>
...
</body>
</html>