I am trying to test receive JSON webhooks from Stripe.
I have read:
Stripe Webhook on Rails
https://stripe.com/docs/webhooks
They require a 200 status response in order to acknowledge receipt.
I want to solve this before moving on to dealing with the JSON.
routes
post 'webhook' => 'web_hook#webhook'
controller
Stripe.api_key = "sk_test_whatsupbuttercup"
class WebHookController < ApplicationController
protect_from_forgery :except => :webhook
def webhook
render status: 200
end
end
With this setup, when I test a webhook, Stripe receives a 500 error.
If you only want to return a status use
head :ok
Instead of render. :ok is the corresponding symbol for 200 but you can also use it with the status code itself.
head 200
A full list of codes and corresponding symbols can be found here...
http://guides.rubyonrails.org/layouts_and_rendering.html
Whenever you get a 500 error (or any time you're confused about how your app is behaving actually) you should look in your logs. In this case you'll probably find that there's an ActionView::MissingTemplate error because you're rendering but not including anything to render.
Related
building a custom rails api for a rails/react/mongodb app.
GET requests working fine, but I can't get post to work.
Basically the params are not getting assigned to the object in my create method.
Request:
POST http://localhost:3000/api/v1/movies HTTP/1.1
{"title" : "Cool Movie"}
Here's my controller:
def create
movie = Movie.new(movie_params)
if movie.save
render json: MovieBlueprint.render(movie)
else
render json: { error: movie.errors.full_messages }, status: 422
end
end
private
def movie_params
params.except(:format).permit(:title, :description, :director, :genre)
end
output:
Parameters: {"{\"title\" : \"Cool Movie\"}"=>nil}
Unpermitted parameter: :{"title" : "Cool Movie"}
I get a 200 response with this. Basically the document is getting created in the database, but the fields / values are all still null. Why is it telling me unpermitted params?
And I know typically with rails you have to require the object like so:
params.require(:movie).permit(:title, :description, :director, :genre)
But when I try this, it makes matters worse, I get a 400 - bad request with this:
ActionController::ParameterMissing (param is missing or the value is empty: movie):
I assume this has something to do with the whole mongo thing and how I'm formatting my request, but I can't quite place it. Any help is appreciated.
At a glance and considering the params coming into the controller via a POST request needs to reference the entity it's changing, your data would need to should look like this to be available in the create method:
{ "movie": { "title": "Updated Song Title" } }
Depending on the version of Rails being used, you could add a debugger to test if the params are available. This will stop the runtime of the script and allow you to inspect it in the terminal.
Run your server in an individual process before trying this. For example, instead of running bin/dev run bin/rails server -p 3000.
First, modify your create method to use debugger:
def create
movie = Movie.new(movie_params)
debugger # <- Stop the script right here.
if movie.save
render json: MovieBlueprint.render(movie)
else
render json: { error: movie.errors.full_messages }, status: 422
end
end
Then, run the create action of your controller by making a request to that endpoint with your params of choice. Navigating to your terminal you'll see the program has stopped and you can type. Type params.inspect to see if the movie key is present:
params.inspect
Type continue to let the rest of the program run.
If a parameter that's required is missing using strong parameters, the Rails server will respond with an HTTP 500.
This does not give me control over giving the user feedback with what exactly went wrong. Does it not make sense to be able to send them back a message such a required parameter is missing?
What is the "Rails way" of giving appropriate user feedback on ActionController::ParameterMissing? Is one supposed to capture the exception and handle your request response there? It seems wrong to do that in every controller.
You can use
rescue_from ActionController::ParameterMissing do |e|
render 'something'
end
in your ApplicationController (or whatever your parent controller is).
As to whether you should inform users or not, I think it depends on what your controllers are doing. If they are API controllers, it definitely makes sense to handle that gracefully, as the users are responsible for preparing the input.
If they are accepting data from your HTML forms it's, in my opinion, not that important as the missing parameters probably mean that the user tinkered with the HTML, or something went really wrong inside the browser.
Since you mention wanting to communicate the error specifics back to the user, you could do something like the following:
# app/controllers/application_controller.rb
rescue_from ActionController::ParameterMissing do |exception|
render json: { error: exception.message }, status: :bad_request
end
You can also define a method to handle a specific exception, if you'd prefer to break up the handling logic:
# app/controllers/application_controller.rb
rescue_from ActionController::ParameterMissing, with: :handle_parameter_missing
def handle_parameter_missing(exception)
render json: { error: exception.message }, status: :bad_request
end
Both of the above examples will return a JSON response like so: {"error"=>"param is missing or the value is empty: [field_name]"}
For an API-only application, I think this is valuable information to pass on.
More info:
Rails API rescue_from documentation
Handling Errors in an API Application the Rails Way
I have a test that checks if the requested page returns a 200 status code:
expect(response).to have_http_status(:success)
However, if I explicitly return a different status code using the following the test:
return render json: { error: 'error message' }, status: :unprocessable_entity
it still passes.
Why do response and last_response have different statuses:
response.status # 200
last_response.status # 422
response is provided by ActionController::TestCase.
From the docs:
An ActionDispatch::TestResponse object, representing the response of the last HTTP response.
For reference, here are the rspec docs for controller tests. This may help clear up how response is supposed to be used.
last_response comes from Rack::MockResponse < Rack::Response
From the docs:
Return the last response received in the session. Raises an error if no requests have been sent yet.
In your test case, you probably used a method that allows you to mock visiting a page. This will set your response.status to 200 as you've had a successful request. If you then use Rack to stimulate an endpoint, e.g.:
put '/users', {my_user: 'blah'}
and you do it with incorrect parameters, then your last_response.status will be 422.
Ultimately, the confusion comes down the similarity of naming between ActionController and Rack::MockResponse, which I agree is rather confusing.
When Rails responds to an HTTP request, it's HTTP response will always be correctly headed up with an appropriate HTTP response code. This can be for successful operations (a 2xx code), such as the creation of a new ActiveRecord in the database, or for errors (a 4xx). In the latter case a rendered HTML page is supplied containing information about the error (a backtrace, etc).
My app requires that all Rails HTTP responses take the form of JSON, so I am writing my own code to render these HTTP responses accordingly. A number of tutorials talk about writing something like this to render such responses (in this example, located in user_account_controller.rb where UserAccount is the name of an ActiveRecord model):
# method to create a UserAccount object based on supplied user_account_params
def create
#user_account = UserAccount.create!(user_account_params)
if #user_account
render :status => 201, :json => {
'message' : 'Operation was successful!"
}
end
end
And, if an exception is thrown, it is possible to bind a customer exception handler as follows:
# In ApplicationController
rescue_from Exception, :with => :json_exception_handler
def json_exception_handler(exception)
render :status => 422, :json => {
:exception => {
:backtrace => exception.backtrace,
:message => exception.message
}
}
end
The problem with both of these solutions is that they require me to statically set the HTTP response codes to have the same value every time (201 and 422 in these examples). Rails already does a great job of automatically picking the best response code to use, depending on the type of error or type of successful operation. I don't want to have to reinvent the wheel badly by inventing my own response code structure for each error and operation in my app.
So my question is this: how do I supply the response code that Rails will have automatically chosen anyway, whilst retaining the ability to print out custom JSON?
Just being very basic here. I'm trying to post an activeResource as Json and recover it on the other side. At present, I seem to be able to send JSON but not recreate it into an Object of my choice.
I've tried my hand at generating a post request with Json in Ruby.
There are 2 parts to be aware of, The active resource on client side and the controller handling the incoming request. The errors usually come down to 406 (request not acceptable) or 422 (Unprocessable Entity)
I suppose the basic question is how can I fix these?
Here is my active resource class.
class UserRequest < ActiveResource::Base
self.site = "http://localhost:3008"
self.format = :json
#do not define defs as 'self'.whatever
def post_me
res = Net::HTTP.post_form(URI.parse('http://127.0.0.1:3008/user_requests.xml'),
{'url' =>'www.stackoverflow.com', 'depth' => '50'})
end
end
#Just to clarify. If im sending Json, I change the URI to .json and If I'm using xml, I #remove the self.format because active resource is XML by default
and here is line in controller which turns it to active record. controllers titled UserRequestsController
def add_request
#user_request = UserRequest.new(params[:user_request])
.
.
. end
route is
match '/user_requests(.:format)' => 'user_requests#add_request', :via =>:post
Now a few things before everyone face palms and goes mad at me.
I'm aware that in the def for add_request I'm missing JSON.parse. This is because when I include it I get 500 and an uninitialized constant error on server side. The gem is definitely installed and I'm not the only one whos had the problem but sadly no fixes.
http://railsforum.com/viewtopic.php?id=4654
http://railsforum.com/viewtopic.php?id=28301
So theres one question is how do i fix the parse so that it works the way I want to as I'm assuming the 406 is because its receiving Json but not sending it.
This would be ideal however if its not possible or someone can think of a reason why I should use XML, then perhaps they could take a look at this and tell me why I might be getting it on server side
Started POST "/user_requests.xml" for 127.0.0.1 at Thu Jul 14 09:38:34 +0100 2011
Processing by UserRequestsController#add_request as XML
Parameters: {"depth"=>"50", "url"=>"www.stackoverflow.com"}
SQL (0.2ms) SELECT 1 FROM "user_requests" WHERE ("user_requests"."url" IS NULL) LIMIT 1
Completed 422 Unprocessable Entity in 18ms (Views: 3.9ms | ActiveRecord: 0.2ms)
Just one last thing is the reasoin I'm not using .save is because the lead on my intern program doesn't like and says its not fit for purpose.
I had a similar problem. Try modifying your "add_request" method like this:
def add_request
#user_request = UserRequest.new(params[:user_request])
format.json { render :json => #user_request, :status => :created, :location => #user_request }
end