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
Related
When a user POSTs JSON to the /update/ action in a Rails 3 app, what is the best way to respond?
I want to just send an empty JSON response with a 200 code, something like
head :no_content
or
render :nothing => true, :status => 204
(examples from How to return HTTP 204 in a Rails controller).
Typically I have been doing this:
render :json => {}
or
render :json => 'ok'
Is there preferred or more Rails-y way to this?
My Rails 3 app uses code such as this for updates. The code for html and xml was auto generated by Rails, so I just added in the JSON renderer using the same format.
respond_to do |format|
if #product.update_attributes(params[:product])
format.html { redirect_to(#product, :notice => 'Product was successfully updated.') }
format.xml { head :ok }
format.json { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #product.errors, :status => :unprocessable_entity }
format.json { render :json => #product.errors, :status => :unprocessable_entity }
end
end
Works perfectly, which is what's ultimately important.
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
I'm trying to set up jquery file upload on a Rails 3.2 app, following this guide.
Everything is almost working perfectly but, when I click "start upload" I see an error in Chrome's console:
POST http://testapp.dev/photos 500 (Internal Server Error)
In the log I'm getting:
ActionView::MissingTemplate (Missing template photos/create, application/create with {:locale=>[:en], :formats=>[:js, :html], :handlers=>[:erb, :builder, :coffee]}.
I've been through the controller with a fine tooth comb, but I can't work out what is causing this error or why its looking for a create partial. What is a systematic way to debug this?
Thanks
EDIT
My controller actions look like this:
class PhotosController < ApplicationController
def index
#photos = Photo.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #photos }
format.json { render :json => #photos.collect { |a| a.to_jq_upload }.to_json }
format.js { render :json => #photos.collect { |a| a.to_jq_upload }.to_json }
end
end
def show
#photo = Photo.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #photo }
format.json { render :json => #photo }
format.js
end
end
def new
#photo = Photo.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #photo }
format.json { render :json => #photo }
format.js
end
end
def edit
#photo = Photo.find(params[:id])
end
def create
#photo = Photo.new(params[:photo])
respond_to do |format|
if #photo.save
format.html {
render :json => [#photo.to_jq_upload].to_json,
:content_type => 'text/html',
:layout => false
}
format.json { render :json => [ #photo.to_jq_upload].to_json }
format.js
else
format.html { render :action => "new" }
format.xml { render :xml => #photo.errors, :status => :unprocessable_entity }
format.json { render :json => [ {:error => "An error was encountered while processing your photos. Please try again."}], status: 304 }
format.js
end
end
end
def update
#photo = Photo.find(params[:id])
respond_to do |format|
if #photo.update_attributes(params[:photo])
format.html { redirect_to(#photo, :notice => 'Asset was successfully updated.') }
format.xml { head :ok }
format.json { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #photo.errors, :status => :unprocessable_entity }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /assets/1
# DELETE /assets/1.xml
def destroy
#photo = Photo.find(params[:id])
#photo.destroy
respond_to do |format|
format.html { redirect_to(photos_url) }
format.xml { head :ok }
format.json { render :json => true }
format.js
end
end
end
It looks like the respond_to block is hitting format.js which will attempt to render a template (a default if no options are provided).
Because the jQuery-file-upload plugin you're using requires a particular JSON response, having a respond_to block seems unnecessary and you can get away with the following
def create
#photo = Photo.new(params[:photo])
if #photo.save
render :json => [ #photo.to_jq_upload].to_json
else
render :json => [{ :error => "An error was encountered while processing your photos. Please try again." }], :status => 304
end
end
I would also highly recommend the debugger gem which will allow you to set breakpoints within the application so you can better tell what is happening.
To add the debugger gem, you'll need to first add the gem to your Gemfile and run a bundle install from the command line. Next, you simply add the word debugger on the line of code you want to set the breakpoint at. In your case, you could do
def create
#photo = Photo.new(params[:photo])
debugger
if #photo.save
# ... rest of code
Finally, you'll need to restart the server with the --debugger option. When the jQuery-file-upload plugin posts the request to the server, it'll hit the breakpoint and you can better analyze the passed params as well as step through the code to get an idea of what is happening. Cheers.
In our rails application we have a page where upon submit we save data in db. On this page, we have some fields which are dynamically generated and I see that in case of a validation error when page reloads it doesn't populate these fields with the values present upon posting.
In controller we have the following method defined for populating it:
def build_my_registration_type_memberships
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end end
In above method when my registration is opened in edit/view mode, it shows the values using this #membership method. But on posting in case of error it doesn't reload this with correct information. So my question is how could I repopulate #membership in case of an error on posting?
Thanks for help.
As, I understand you want some values available to your new method or the page that is rendered after if the create fails.
I assume you must have have the respond_to block in your create method. And you're doing this:
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html { render :action => :new }
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
As you can notice, in the else part the new action is just rendered. Using some template the view is just delivered. Now, you just have to do whatever you're doing in the new action to make those values available, in the else part.
def create
...
respond_to do |format|
if #patient.save
format.html { redirect_to #object, :notice => "Object was successfully saved." }
format.xml { render :xml => #object, :status => :created, :location => #object }
else
format.html {
#memberships = []
ListCache.my_registration_types.each do |my_registration_type|
#memberships << MyRegistrationTypeMembership.find_or_initialize_by_my_id_and_my_registration_type_id( #my.id, my_registration_type.id )
end
render :action => :new
}
format.xml { render :xml => #patient.errors, :status => :unprocessable_entity }
end
end
end
And, the values you wanted will be available in the rendered form.
Better, you move to that code to a before filter or something, which makes those values available to those two methods (new and create).
Given a classic controller action. Have a look at the MARK. I need to set the status code to 200 for the response. Background: swfupload an ajax file upload solution seems to send data in a wrong format.
I tried response.headers['Status'] = 200, response.status 200, render :json => 'data', :status => 200. But the response's status code doesn't change.
def create
if params[:Filedata]
#medium = Medium.new(:swf_uploaded_data => params[:Filedata])
else
#medium = Medium.new(params[:medium])
end
respond_to do |format|
if #medium.save
format.html { redirect_to(#medium, :notice => 'Medium was successfully created.'); }
format.xml { render :xml => #medium, :status => :created, :location => #medium; }
MARK
else
format.html { render :action => "new" }
format.xml { render :xml => #medium.errors, :status => :unprocessable_entity }
end
end
end
The status code can only be declared within the return commands like render, redirect_to .... and will affect to this return command, there is no way to set the code for all the responses
For format.html { redirect_to(#medium, :notice => 'Medium was successfully created.'); } since is a redirection the code will be a 3XX and you can't change it or the redirection won't work
For format.xml { render :xml => #medium, :status => :created, :location => #medium; } you are declaring the status as created, this means for rails that the code is 201, for making it a 200 change it for:
format.xml { render :xml => #medium, :status => :ok, :location => #medium; }
What format is the AJAX call expecting in response? You're only responding to HTML and XML, so if it's expecting JavaScript or JSON, that might be a problem.
Also, I'm not sure if this matters, but I've never seen a condition inside the respond_to block like you've shown. Usually it's like this:
if #medium.save
respond_to { |format| ... }
else
respond_to { |format| ... }
end
I'm also not clear what the "MARK" is supposed to be.