Rails and Active Model Serializers: prevent double JSON encoding and escape characters (\) - ruby-on-rails

In one of my controllers I manually assemble my JSON data to be able to use AMS custom serializers:
data[:foos] = {}
Foo.find(foo_ids).each do |f|
data[:foos][f.id.to_s] = render_to_string :json => f, :root => false, :serializer => FooCustomSerializer
end
data[:moos] = {}
Moo.find(moo_ids).each do |f|
data[:moos][f.id.to_s] = render_to_string :json => f, :root => false, :serializer => MooCustomSerializer
end
result = {:system => system_info, :content => data}
respond_to do |format|
format.json { render json: result }
end
It works, but the problem is it encodes twice the Moos and Foos, and the JSON rendered has plenty of escaped characters:
{ "system":"OK",
"content":
"foos":"[{\"name\":\"Rex\",\"breed\":\"Lab\"},{\"name\":\"Spot\",\"breed\":\"Dalmation\"},{\"name\":\"Fido\",\"breed\":\"Terrier\"}]"
...
Is there a way to prevent this?

Just put .to_json after the hash variable.
Example:
format.json { render json: result }
# Change to
format.json { render json: result.to_json }

Related

Pretty format my JSON output in Rails 4

I am using pretty_generate in my controller, but I am getting the following error
'only generation of JSON objects or arrays allowed'
#celebrities = Celebrity.includes(:category)
respond_to do |format|
format.json { render json: JSON.pretty_generate(#celebrities.to_json(:include =>{:category => {:only => [:category]} })) }
end
I am not sure why I am getting this error
As the error suggest, only generation of JSON objects or arrays allowed. I guess you should try this.
#celebrities = Celebrity.includes(:category)
respond_to do |format|
format.json { render json: JSON.pretty_generate(JSON.parse(#celebrities.to_json(:include =>{:category => {:only => [:category]} })))}
end

Rails TemplateMissing when exception occurs

I have the following code segment
def range
respond_to do |format|
if params[:start] && params[:end]
begin
dstart = Time.parse(params[:start])
dend = Time.parse(params[:end])
rescue => e
format.json { render :json => { :status => :unprocessable_entity, :error => e.message }} and return
end
...
And it works totally fine and makes it to the stuff at the bottom...
...
format.json { render :json => { :status => :ok, :posts => #res.to_json(:only => [:date, :content, :user_id]) } }
else
format.json { render :json => { :status => :unprocessable_entity, :error => "must have a _start_ and _end_ date" } }
...
The problem is when an exception occurs and the rescue section is called, Rails does not respond with json but instead tells me "Template Missing." Is something wrong with my syntax?
D'oh, turns out I don't need the format.json bit. Why, exactly, though?
Consider this example regarding show action to understand the error
class ModelsController
.
.
def show
#model = Model.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
end
In this case, if the request is of type html then rails by convention searcher for a file
app/views/models/show.html.erb.
But if the request is of type js then rails will search for app/views/models/show.js.erb.
If these files does not exist then rails will throw template missing error
so if you are only responding to json then you can do
respond_to do |format|
format.json do
begin
..
rescue
render :json => { }
end
end

rails 3 - How to render a PARTIAL as a Json response

I want to do something like this:
class AttachmentsController < ApplicationController
def upload
render :json => { :attachmentPartial => render :partial => 'messages/attachment', :locals => { :message=> #message} }
end
Is there a way to do this? render a Partial inside a JSON object? thanks
This should work:
def upload
render :json => { :attachmentPartial => render_to_string('messages/_attachment', :layout => false, :locals => { :message => #message }) }
end
Notice the render_to_string and the underscore _ in before the name of the partial (because render_to_string doesn't expect a partial, hence the :layout => false too).
UPDATE
If you want to render html inside a json request for example, I suggest you add something like this in application_helper.rb:
# execute a block with a different format (ex: an html partial while in an ajax request)
def with_format(format, &block)
old_formats = formats
self.formats = [format]
block.call
self.formats = old_formats
nil
end
Then you can just do this in your method:
def upload
with_format :html do
#html_content = render_to_string partial: 'messages/_attachment', :locals => { :message => #message }
end
render :json => { :attachmentPartial => #html_content }
end
This question is a bit old, but I thought this might help some folks.
To render an html partial in a json response, you don't actually need the with_format helper as explained in mbillard's answer. You simply need to specify the format in the call to render_to_string, like formats: :html.
def upload
render json: {
attachmentPartial:
render_to_string(
partial: 'messages/attachment',
formats: :html,
layout: false,
locals: { message: #message }
)
}
end
In Rails 6 I think this might be a little different from the accepted answer. I don't think you need to set the underscore in the partial name. This worked for me:
format.json {
html_content = render_to_string(partial: 'admin/pages/content', locals: { page: #page }, layout: false, formats: [:html])
render json: { attachmentPartial: html_content }
}

Is it a bug for method hash#to_json in Rails?

I use rails 2.3.8
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => ({ :results => #posts.size, :rows => #posts.to_json(:only => [:id, :title, :click_count, :body])}).to_json }
end
end
the generated json data is:
{"rows":"[{\"title\":\"ruby\",\"body\":\"goood\",\"click_count\":1,\"id\":1},{\"title\":\"g\",\"body\":\"h\",\"click_count\":1,\"id\":2}]","results":2}
but in fact is shuld be:
{"rows":[{\"title\":\"ruby\",\"body\":\"goood\",\"click_count\":1,\"id\":1},{\"title\":\"g\",\"body\":\"h\",\"click_count\":1,\"id\":2}],"results":2}
is it a bug in rails?
and now how can to_json generate the expected json data for me?
Thanks!
Sorry,it was my fault.
the action code should be
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => ({ :results => #posts.size, :rows => #posts.map{|x| x.attributes}).to_json } }
end
end
That is to say: the value of key :rows must be an array object!
Thanks hoooopo!

Test rails controller that respond in different formats

I have the following function in controller
def by_xy
#obj = BldPoly::find_by_xy(:x => params['x'], :y => params['y'])
respond_to do |format|
format.html { render :layout => false }
format.xml { render :layout => false }
format.json { render :layout => false }
end
and planning to write the automatic test in the following way
xml = nil
get :by_xy, {:x => 4831, :y => 3242, :format => :json}
assert_nothing_thrown { xml = REXML::Document.new(#response.body) }
td = REXML::XPath.first(xml, "//result/item")
assert_equal need_value, td.value
and I get
Completed in 50ms (View: 0, DB: 230) | 406 Not Acceptable [http://test.host/search/by_xy/4831/3242.json]
when I missed format in testing code - all works correctly,
how should I write the test?
I figured this out, actually; this is how it should be
get :by_xy, {:x => i[:x], :y => i[:y]}, :format => :json
For rails 5.1, when doing a post, I had to include the format attribute inside of my params hash
share_params = {
email: nil,
message: 'Default message.'
format: :json
}
post image_share_path(#image), params: share_params
assert_response :unprocessable_entity
If not I would get the error ActionController::UnknownFormat inside of my create controller
def create
#image = Image.new(image_params)
if #image.save
flash[:success] = 'Your image was saved successfully.'
redirect_to #image
else
respond_to do |format|
format.json do
render json: { #image.to_json },
status: :unprocessable_entity
end
end
end

Resources