Rails: return only integer in get method - ruby-on-rails

I am trying to setup Facebook's webhook, and when specifying the callback url, they send a get request to it and expect to receive a code.
I defined an action:
def webhook
render json: { code: '1234567890' }
end
So the reponse to the request is { code: '1234567890' } when they are expecting '1234567890'.
I tried to only have:
def webhook
render json: {'1234567890'}
end
But I get an error.
I also tried to use the head method but nothing is sent back.
How can I only send back an integer ?

As Nani pointed it out in the comments:
def webhook
render :json => 1826416246
end
Works fine !

Related

Ruby API response view : how can I render a JSON response?

I'm new to Ruby, trying to building an API.
I've followed a tutorial and was able to return a JSON response when calling an API endpoint.
In this example, the function called raises an error that I want to pass as a JSON response.
my_controller.rb
class MyController < ApplicationController
def getTracklist
begin
importer = #this raises an error
rescue StandardError => e
#response = {
error: e.message,
}
return #response
end
end
end
my view look like this :
getTracklist.json.jbuilder
json.response #response
thing is,
this works but renders my response as
{"response":{"error":"the error message"}}
while I want it as
{"error":"the error message"}
I made an attempts by changing my view to
json #response
but it fails :
ActionView::Template::Error (undefined method `json' for
<#:0x0000559304675470> Did you mean? JSON):
1: json #response
So how could I render my response "fully" without having to put it in a property ?
I've also seen when reading stuff about ROR that this code is sometimes used, and I was wondering how I could use it in this situation :
render json: { error_code:'not_found', error: e.message }, status: :not_found
Thanks !
There are multiple ways of achieving what you want. You could merge! the response into the jbuilder root.
json.merge! #response
The above merges all key/value-pairs into the jbuilder root. You could also opt to extract! specific attributes.
json.extract! #response, :error
Alternatively you can simply render it in the controller, since you've already composed the structure the following would be enough.
render json: #response
You can do this for jBuilder:
json.merge!(#response)
Source
class MyController < ApplicationController
def getTracklist
begin
# you need to assign something to a variable
rescue StandardError => e
respond_to do |format|
format.any(:json, :js) do
render :json => {:error => e.message}
end
end
end
end
end
Making these changes to your controller can help you with your requirements.
You don't need a view after doing this.

Why is yield not passing the result to block (Rails)?

I know there are several SO questions as well as online articles on using yield in Rails. But I'm still having trouble understanding what's wrong with my code below, and would appreciate any advice.
In my app, I have:
A controller that passes data to the command class's run method, and returns the request status based on the result of the Command.run (true/false)
A command class that deals with the actual meat of the process, then yields true if it succeeded, or false if it failed
However, the command class seems to be failing to yield the results to my controller. According to the error messages when I run my tests, it seems like my block in the controller isn't being recognized as a block:
# If I use "yield result":
LocalJumpError: no block given (yield)
# If I use "yield result if block_given?":
# (This is because I have "assert_response :success" in my tests)
Expected response to be a <2XX: success>, but was a <400: Bad Request>
How should I rewrite the block (do ... end part in the controller below) so that yield works correctly? Or if the issue lies elsewhere, what am I doing wrong?
I've provided a simplified version of my code below. Thank you in advance!
# controller
def create
Command.run(params) do
render json: { message: 'Successfully processed request' }
return
end
render json: { message: 'Encountered an error' }, status: :bad_request
end
# command class
def run(params)
# Do some stuff, then send HTTP request
# "result" below returns true or false
result = send_http_request.parsed_response == 'ok'
yield result
end
def self.run(params)
new.run(params)
end
Note: This code works if I use if true... else... in the controller instead of a block, and just return the boolean result instead of yielding it. But here I'd like to know how to make yield work.
In your controller you need to have a variable for the result.
def create
Command.run(params) do |result|
if result
render json: { message: 'Successfully processed request' }, status: :success
else
render json: { message: 'Encountered an error' }, status: :bad_request
end
return
end
render json: { message: 'Encountered an error' }, status: :bad_request
end
(EDIT)
Also, you are calling the class method which call the instance method. You have to pass the block from the calling code to the instance method you are calling.
def self.run(params, &block)
new.run(params, &block)
end
EDIT: ah, so you have a class method run and instance method run.
Either do as Marlin has suggested and supply the block explicitly from class method to the instance method.
Or use only the class method as I've initially suggested (it doesn't
seem like there's any reason to instantiate Command in your case):
def self.run(params, &block)
result = send_http_request.parsed_response == 'ok'
block.yield(result)
end

DoubleRenderError when use render in both called and caller method in Rails

I am a newbie with Ruby on Rails.
This code returns DoubleRenderError:
class PostapisController < ApplicationController
def method1
method2()
render json: {:success: false}
end
def method2
render json: {:status => 'ok'} and return
end
end
Why does it return DoubleRenderError? How can I fix it if I still want both method1() and method2() to call render?
"render" and "redirect_to" are both ways to generate the response to the request your server received. The server can only give one response to each request, so you can't render twice.
In your case, you should be able to appreciate that it doesn't make sense to send a {:success: false} response AND send a {:status => 'ok'} response: it's got to be one or the other, right? That's not a rails thing, it's just a web thing. One response per request.
I don't know what you're trying to achieve, so can't advise any further, other than by telling you to read some more basic stuff about Rails before starting to use it.

Refactor and callback

In one controller I got a method that I want to refactor to share with other controllers. At the same time, I'm passing it to the callback before_action.
app/models/meal_controller.rb
def check_for_user
token = request.headers[:token]
if token.nil?
render json: "Unathorized", status: 401
elsif #meal.user.auth_code != token
render json: "Forbidden", status: 403
end
end
So my approach was move check_for_userto the ApplicationController and modify it as follows:
def check_for_user(item)
token = request.headers[:token]
if token.nil?
render json: "Unathorized", status: 401
elsif item.user.auth_code != token
render json: "Forbidden", status: 403
end
end
And back to the MealController, create a other "dummy" method without params and call the check_for_user.
def check_for_user_meal
check_for_user(#meal)
end
My question is: is there a better way to refactor this code?
Thanks in advance.
I have no problem with your code going in ApplicationController, if it's only a few lines of code.
However, I'd suggest you check the difference between 401 and 403. The main difference is that 401 means there was an error with your authentication attempt, please try again; whereas 403 means you are trying to authenticate in a way that is incorrect so please stop trying.
With a username/password user input, 401 makes sense because its likely the user has mistyped something.
But with tokens, another attempt is only going to get the same result. So both no token and the wrong token should result in a 403 error.
So I'd refactor you code like this:
def request_token
request.headers[:token]
end
def check_for_user(item)
if request_token.nil? || item.user.auth_code != request_token
render json: "Forbidden", status: 403
end
end
You could create a module so the method would be available across the application.

How do you respond with JSON in a Rails API when you need to respond with error information?

For example...
module Api
module V1
class SessionsController < ApplicationController
respond_to :json
skip_before_filter :verify_authenticity_token
def create
#user = User.find_by(email: params[:session][:email].downcase)
if #user && #user.authenticate(params[:session][:password])
token = User.new_remember_token
#user.update_attribute(:remember_token, User.digest(token))
respond_with :api, :v1, _____________
else
#error
end
end
end
end
end
The #error part of the code, if the user is not properly authenticated. What syntax do I need to properly convey to the caller that the authentication did not go through for example, or in other cases, maybe data was not saved?
Like CBroe said, respond with an appropriate status code, such as 400 or 403. You could do just that (using 'head' to return the status code only), or also add an error message in JSON format:
{ 'error' : 'Authorization failed' }
The client code will want to check the status code and possibly the 'error' key in the JSON response and handle it appropriately.
Examples to put at the end of your controller action (pick one):
return head(:bad_request) # returns a 400 status code only
render :json => { :error => 'That was an invalid request' } # defaults to 200 status
render :json => { :error => 'Oops! Bad request' }, :status => 400
The last example overrides the default status to make it a 400. In general, the status can be an integer like that, or a symbol like :not_found or :bad_request. Hope that helps.

Resources