Force Omniauth to use json for callback? - ruby-on-rails

I'm attempting to integrate Omniauth into an API written in rails, to be used by an Android application. This means that I want to be able to handle the omniauth callback with JSON.
By default, Omniauth sends its callbacks to /auth/:provider/callback, is there a way that I can force Omniauth to instead send its callbacks to /auth/:provider/callback.json?

You can specify format in action where handling callback:
# in route.rb
match '/auth/:provider/callback' => 'authentications#create'
# in authentications_controller.rb
class AuthenticationsController < ApplicationController
def create
# your code here
respond_to do |format|
format.json { ... } # content to return
end
end
end

I managed to do that by inspecting the request object on my rails backend.
When I make the request on my app, I add data on the submition defining the format:
format: "json"
And the omniauth then makes the callback for
/auth/:provider/callback
Wich in my case matches
sessions#create
as an HTML request. But once there, if you look at your request object in rails, and search for the omniauth.params hash you'll see that one of the values there is the format passed on tha data of the initial request:
"omniauth.params"=>{"format"=>"json", "provider"=>"facebook", "code"=>"..."}
Its a mather of you searching for this "format"=>"json" and doing a render json as an answear.
I hope it solves your problem.

# app/controllers/users_controller.rb
def authenticate
#credentials = request.env['omniauth.auth']
render json: #credentials
end
# config/routes.rb
get '/auth/:provider/callback', to: 'users#authenticate', as: 'user_auth'
And then all requests made to /auth/:provider/callback will return a JSON response by default.

Related

Devise - how to 'after confirmation path' return json respond.

I have an API made with RUBY using Devise to handle authentication.
Also I'm using :confirmable property but I'm having some trouble to get a respond.
I'm doing a GET request, sending the validate token to devise/confirmations#show, which works fine because after that I try to get into my app and I can. The thing is, when I send that request, I'm getting a respond error cause I don't have any redirect route cause I'm not using any views (is an API)
I try to create a new class from devise:
class ConfirmUserController < Devise::ConfirmationsController
private
def after_confirmation_path_for(resource_name, resource)
respond_to do |format|
format.json { render json: {msg: 'success'} }
end
end
end
Basically what I need is when a user confirms their account, the api should send a 'success' message to my app. I don't want to redirec to another view.
How can I do that?
Having a look at the source should explain why this doesn't work. Your respond_to block is in the wrong place and therefore not having any effect.
You are overriding after_confirmation_path_for which should return a path, but respond_with_navigational in #show is a parameter of redirect_to, which will redirect regardless of what is returned.
Since you already have a custom controller, I suggest that you override the #show action too, and respond with JSON directly from there.

Any alternative to redirect_to in rails api only application?

I would like to redirect to another url in rails controller action. like
def action_name
redirect_to url
end
I know i can do it simply using the above method. But i want to redirect in only one action in all my application. because of this i don't want to include this in controller.
include ActionController::Redirecting
is there any other way to redirect to a uri in api only applications. Thanks.
You can use respond_with which will respond with a appropriate response depending on the request type and the status of the model you pass to respond_with.
def create
#thing = Thing.create(thing_params)
respond_with(#thing)
end
This will give 201 - Created status and a location header if the the request is successful and a 422 - Unprocessable Entity if the validations fail.
Alternativly you can use head to send a header only response with no body.
def action_name
head :not_found, location: url
end
Note that :not_found could be any appropriate HTTP status.
If your using Rails API:
Route your path, and take the params, and return:
redirect_to controller: "client", action: "get_name", params: request.query_parameters and return

Ruby on Rails: Pass Parameters to View

When a user makes a request to the url /mobile in my Rails app, I would like a parameter to automatically be appended to the URL that gets loaded after the request (something like /mobile?tree_width=5)
I have tried a few things, all of which have not worked.
The closest I have gotten is this in my controller:
def mobile
respond_to do |format|
format.html{
# pass tree width here
render mobile_project_steps_path(#project, :tree_width => #project.tree_width)
}
end
end
I am getting the error
Missing template /projects/8/steps/mobile?tree_width=5
But I think this path should exist according to my rake routes:
mobile_project_steps GET /projects/:project_id/steps/mobile(.:format) steps#mobile
How do I add a param to the URL from a controller?
You need to check if the param is missing and if it is redirect to current action with extra param. I would squeeze it with in before_action:
before_action :check_tree_width, only: :mobile
def mobile
# Your actual logic
end
private
def check_tree_width
redirect_to(tree_width: #project.tree_width) unless params[:tree_width].present?
end

Staging subdomains when application already has subdomains

My current Rails application has the following subdomains:
ui.myapp.com
api.myapp.com
I want to set up a staging environment, and I am wondering what is the best approach in order to set the domains.
Usually, I would do:
staging.myapp.com
But then, how do I access the UI/API sites?
Is it 'ok' to do:
ui.staging.myapp.com
api.staging.myapp.com
?
Assumption: The output from API call is expected in JSON format.
It will not be advisable to use separate subdomain for functionality like api.staging.myapp.com. You can always use the same url for web application and API
Better way would be to use same controller-action from Rails application but instead to return JSON output hash.
For example to get the users, you will have some code in users_controller.rb as
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html do
render :index
end
format.json do
render :json => {:users => #users}
end
end
end
end
Now here if the request is html it will render the html page else it will return the json response.
staging.myapp.com/users will get you the html page of web application displaying users collection and that of staging.myapp.com/users.json will provide you the json response hash of users collection.
So, you will not need different subdomain to distinguish the api and normal site. But using format of request you can distinguish the functionality.
I hope this answers your question. If you still have any query feel free to ask.

ROR: sending an object in response

I have 2 ruby on rails apps. With app A I post app B some data (in the form of a hash). I then want app B to send a hash on this data (with some modifications) back to app A in the response.
I have tried the code below App A
response = Net::HTTP.post_form(uri, params)
quotes.push(response.body)
and in App B
details = get_details //returns a hash
respond_with details
But its not working. Is what im doing even possible? Is there a way I can place this hash in my response?
Any help would be appreciated
Solution #1
If you use respond_with you need also specify formats which your app should respond to. For this you should use respond_to method.
Example:
class TestController < ApplicationController
respond_to :json
def index
details = get_details
respond_with(details)
end
end
Also check this good article about respond_to method.
Solution #2
Just use render json: {...} in your controller action.
Example:
class TestController < ApplicationController
def index
details = get_details
render json: details
end
end
In your app A response.body will contain a string with the data from your app B. So you need to parse that string.
In your app A:
require 'json' # this is unnecessary if app A is a Rails app
response = Net::HTTP.post_form(uri, params)
parsed_response = JSON.parse(response.body)
quotes.push(parsed_response)
The rails way to do that is using JSON as an exchange format. have a look at the guides for how to use that: http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-json
It is also possible to use ActiveResource for such a communication. It allows direct access to your rails API.

Resources