ActionController::UnknownFormat for json response - ruby-on-rails

Im using this code in my controller to give json response
respond_to do |format|
msg = { :status => "ok", :message => "Success!" }
format.json { render :json => msg }
end
is giving me an error -> ActionController::UnknownFormat on the "respond_to do |format|" line.
In my routes.rb,
Im using this
get '/xyz' => 'xyzs#abc'

Try to do it like:
msg = { :status => "ok", :message => "Success!" }
render :json => msg

Please check whether JSON Mimetype is added to your config/initializers/mime_types.rb
Mime::Type.register "application/json", :json

Check if you have a class level respond_with call in your controller or in ApplicationController. If there is one, check if :json is passed as one of its params.

Related

Rails responds with status code 406

I have been working on a test for my function inside Ruby on Rails. However, the test (which expects a status code of :success) fails after receiving a status code 406. Here's the exact failure log:
Failure: Expected response to be a <:success>, but was <406>.
test_should_post_comment_through_token_successfully(CommentControllerTest)
test/functional/comment_controller_test.rb:271:in `block in <class:CommentControllerTest>'
I read a little about the 406 response, and found out that it stands of "Not Acceptable". so I tried setting the Accept, Content-Type, Accept-Language and Accept-Charset headers but I have had no luck.
Here's the code for my test:
test 'should post comment through token successfully' do
#params = {
id: 1,
body: "Test Comment",
username: "Bob"
}
#headers = {
"Accept" => "application/json",
"Accept-Language" => "en-US",
"Accept-Charset" => "utf-8",
"Content-Type" => "application/json",
"Token" => "abcdefg12345"
}
get :create_by_token, #params, #headers
assert_response :success
end
The create_by_token function inside the controller:
def create_by_token
#node = Node.find params[:id]
#user = User.find_by_username params[:username]
#body = params[:body]
#token = request.headers['Token']
p request.headers["Accept"]
p request.headers["Content-Type"]
p request.headers["Token"]
if #user && #user.token == #token
begin
#comment = create_comment(#node, #user, #body)
msg = {
status: :created,
message: "Created"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
rescue CommentError
msg = {
status: :bad_request,
message: "Bad Request"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
end
else
msg = {
status: :unauthorized,
message: "Unauthorized"
}
respond_to do |format|
format.xml { render xml: msg.to_xml }
format.json { render json: msg.to_json }
end
end
end
My route:
post '/bot/comment.:format', to: 'comment#create_by_token'
Am I missing something crucial? How do I go about solving this issue?
I would be happy to provide any other information you would need.
Seems this might be an error with respond_to do block. Kindly check with the routes whether you have configured as resources or resource.
Do update to resources than singular which will help with respond_to do block.
You can also try update your routes as/;
resources :samples, defaults: {format: :json}
Oh, stupid me. I realized that among all the params I was passing, the format was also being passed inside the URL. However, as in the test I was not mentioning a URL which I could pass in the format as the suffix (.xml or .json), I would have to mention the format inside the params explicitly. Here's the updated test code:
test 'should post comment through token successfully' do
#params = {
id: 1,
body: "Test Comment",
username: "Bob",
format: 'json'
}
#headers = {
"token" => "abcdefg12345"
}
post :create_by_token, #params, #headers
assert_response :success
end
Kudos #Sowmiya for leading me to this conclusion. Your answer was not exactly the solution I needed, but it provoked me to think.

Rails and Active Model Serializers: prevent double JSON encoding and escape characters (\)

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 }

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 }
}

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