How do I render custom error JSON in a Rails 5 API? Right now, if I perform a GET on this url http://localhost:3000/users/5, it returns the 404 not found code, and all the traces associated with it. How can I stop Rails from automatically rendering all the traces?
Example of the generated error response: https://pastebin.com/C1dQA5eL
Hi you can create a custom module and extend it in your controller. Create a method in that module with parameters of resource and value. And on the basis of that send response and after that you can extend it in your respective Controller
like this:
class MyController
include AppError
end
I think you should if....else.
def show
user = User.find_by(id: params[:id])
if user.present?
render json: user
else
render json: { status: :not_found }
end
end
Related
I'm currently using the below to add one product that has a name and a brand via API call. I would like to be able to submit an array of 'products' and then add then to my DB.
Could anyone suggest:
1) How would I do this in the controller?
2) How would I structure the API POST body?
Current call looks like:
http://localhost:3000/api/v1/products?brand=brand&name=name
My Controller:
def create
#newProduct = Product.create(product_params)
if #newProduct.save
render json: {message: "Product created"}
else
render json: {error: "Failed to create product"}
end
end
private
def product_params
params.permit(:name, :brand)
end
Thanks
Add a new route in routes file with line below
get 'create_multiple_products'
Send data in an array
{"products":[
{"name":"playstation"},
{"name":"xbox"},
{"name":"blueray"}
]}
then add a new method in controller and call the create in a loop
def create_multiple_products
response["products"].each do |p|
Product.create( p )
end
end
The above is pseudocode, you might want to try a test driven approach setting up expected api and matching with returned data with rspec. http://matthewlehner.net/rails-api-testing-guidelines/
I'd like a Rails controller (all of them, actually, it's an API) to render JSON always always.
I don't want Rails to return "route not found", or try and fail to find an HTML template, or return 406. I just want it to automatically and always render JSON, e.g. from a RABL or JBuilder view.
Is this possible? Related questions seem to have answers that have the aforementioned downsides.
You can add a before_filter in your controller to set the request format to json:
# app/controllers/foos_controller.rb
before_action :set_default_response_format
protected
def set_default_response_format
request.format = :json
end
This will set all response format to json. If you want to allow other formats, you could check for the presence of format parameter when setting request.format, for e.g:
def set_default_response_format
request.format = :json unless params[:format]
end
You can use format.any:
def action
respond_to do |format|
format.any { render json: your_json, content_type: 'application/json' }
end
end
It's just:
render formats: :json
I had similar issue but with '.js' extension. To solve I did the following in the view:
<%= params.except!(:format) %>
<%= will_paginate #posts %>
I tried the above solutions and it didn't solve my use case.
In some of the controllers of my Rails 4.2 app, there was no explicit render called. For example, a service object was called and nothing was returned. Since they are json api controllers, rails was complaining with a missing template error. To resolve I added this to our base controller.
def render(*args)
options = args.first
options.present? ? super : super(json: {}, status: :ok)
end
It's a large app I'm converting to Rails 5, so this is just a safety measure as I removed the RocketPants gem that seemed to do this automatically.
As a note, my controllers inherit from ActionController::Base
Of course:
before_filter :always_json
protected
def always_json
params[:format] = "json"
end
You should probably put this in a root controller for your API.
I am trying to configure my controller to process the params sent through a POST from another website. My log shows that the parameters that I receive are as follows:
{"page_id"=>"8b62f4ac-8588-11e3-a094-12314000b04c", "page_name"=>"test form", "variant"=>"b", "page_url"=>"http://get.xxxxxxx.com/test-form", "data.json"=>"{\"name\":[\"Dave\"],\"email\":[\"xxxx#me.com\"],\"phone\":[\"4447177265\"],\"ip_address\":[\"64.114.175.126\"],\"time_submitted\":[\"07:34 AM UTC\"]}", "data.xml"=>"\n\n Dave\n xxxx#me.com\n 2507177265\n 64.114.175.126\n 07:34 AM UTC\n"}
Initially I thought that Rails would automatically parse the JSON in the params and I could access them in the normal way. So I wrote the Registrations Controller like this:
class Api::RegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
#user = User.new(user_params)
if #user.save
render json: #user.as_json( email: #user.email), status: 201
return
else
warden.custom_failure!
render json: #user.errors, status: 422
end
end
def user_params
params.require(:'data.json').permit(:email, :name, :phone, :comments, :residency, :qualification, :acknowledgement) if params.present?
end
end
However, it is simply not working at all. I get an error undefined method 'permit' for string. So obviously I'm not accessing the JSON correctly. Is it possible that because the JSON is escaped that it's throwing the errors?
I've been googling and asking in IRC for a couple of days but I'm not any farther ahead.
I can pass a properly formatted JSON to the controller and it works fine (with changes to the require arguments)
I'm stumped since I need to be able to create a new user with the JSON data. Any help would be HUGELY appreciated. I just don't know what direction to even go from here.
The params.require(:'data.json') returns a JSON body which is a string, however your controller does not interpret the string but expects a Hash.
You can convert the JSON string to a Hash object using the parse class method for JSON like so:
require 'json'
JSON::parse(json_string)
I have some basic model validations that are triggered when a form gets submitted by AJAX. If the validations fail, I want to pass the validation errors back to the view so I can tell the user.
def save
logger.debug( params )
#video = Video.new( video_params )
if #video.save
render json: #video
else
render json: errors.messages
end
end
This throws an error because errors is undefined. What am I doing wrong? I read the docs on this and it only shows errors.messages used in the view.
errors is a instance method from an ActiveRecord. The correct way to use in your case is like this:
#video.errors.messages
instead of messages use full_messages, like below
#video.errors.full_messages
I have a model called Entity and the create action in the controller looks like this:
# enitities_controller.rb
def create
# loading params, etc...
#entity.save
respond_with #entity
end
I am using jbuilder for custom JSON views rather than rendering #entity.to_json, which works great. I have one last issue, which is when the model won't save due to validation errors I get the following response (with status 422 Unprocessable Entity):
{"errors":{"parent_share":["can't be blank","is not a number"]}}
I would like to override this json with my own. I am aware of he possibility to replace respond_with #entity with:
respond_with #entity do |format|
if #entity.errors.any?
format.json {
render "entities/create", :status => :unprocessable_entity
}
end
end
But shouldn't there be a more auto-magic way by defining some sort of errors view or something? This feels a bit dirty AND it makes me have to write more code each time I need this rather than allowing me to use respond_with. Is there another way?
Meanwhile I have found the answer:
You have to create the file lib/application_responder.rb and add the following:
class ApplicationResponder < ActionController::Responder
include Responders::FlashResponder
include Responders::HttpCacheResponder
def to_json
set_flash_message! if set_flash_message?
if !has_errors? || response_overridden?
default_render
else
controller.default_render( status: :unprocessable_entity )
end
end
end
And add the following to your application responder:
self.responder = ApplicationResponder
What this does is add a to_json method that will copy the behaviour of the to_js responder.