Using devise to authenticate a API login request via JSON - ruby-on-rails

I'm trying to use devise to authenticate a simple email/password login so users can access the rest of the API via auth tokens. I'm running into trouble with devise simply returning You need to sign in or sign up before continuing. Here's my code:
class LoginController < ApplicationController
respond_to :json
def login
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
render :status => 200,
:json => { :success => true,
:info => "Logged in",
:user => current_user
}
end
def failure
render :status => 401,
:json => { :success => false,
:info => "Login Failed",
:data => {} }
end
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
routes.rb
devise_scope :user do
post 'register' => 'registration#create', :as => :registers
post 'login' => 'login#login', :as => :login
end
I'm sending the following post data:
{
"user" : {
"email" : "testPost4#fake.com",
"password" : "Password1"
}
}
Having browsed various posts I've added:
config.navigational_formats = [:json]
to the devise.rb file but it didn't solve the problem.
Adding skip_before_filter :authenticate_user! doesn't work either.

I wasn't able to get this working so I have reverted to the much simpler approach of checking and signing in manually.
def login
params = login_params
user = User.find_by_email(params['email'].downcase)
if user.valid_password?(params['password']) then
sign_in(user)
success
else
failure
end
end

Related

Setting up an API using Devise for authentication

I am attempting to get a user registration endpoint setup for my rails application so that I can access the app's functionality in an iOS rendition. I've gone ahead and namespaced my API, and so far have managed to get user authentication working using Devise and JWT's.
This is great, however, I also need to ability to register a user via the API. To be frank, I have no idea how to correctly implement this. Several Google searches either bring up outdated articles, use the deprecated token authenticatable, or have never been answered.
Below is the code that I believe pertains most to this question:
routes.rb (Namespaced section for API)
namespace :api do
namespace :v1 do
devise_for :users, controllers: { registrations: 'api/v1/registrations' }
resources :classrooms
resources :notifications
end
end
end
registrations_controller.rb (API contorller)
class Api::V1::RegistrationsController < Devise::RegistrationsController
respond_to :json
def create
if params[:email].nil?
render :status => 400,
:json => {:message => 'User request must contain the user email.'}
return
elsif params[:password].nil?
render :status => 400,
:json => {:message => 'User request must contain the user password.'}
return
end
if params[:email]
duplicate_user = User.find_by_email(params[:email])
unless duplicate_user.nil?
render :status => 409,
:json => {:message => 'Duplicate email. A user already exists with that email address.'}
return
end
end
#user = User.create(user_params)
if #user.save!
render :json => {:user => #user}
else
render :status => 400,
:json => {:message => #user.errors.full_messages}
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute, :first_name, :last_name, :access_code])
end
end
End Point for registration
http://localhost:3000/api/v1/users
Sample Postman response
{
"message": [
"Email can't be blank",
"Password can't be blank",
"Access code is invalid [Beta]."
]
}
Any help would greatly be appreciated, as I am keen on learning more (and getting this to work!).
UPDATE 1
Here is what I get on the server after making a post request to generate a user...
Started POST "/api/v1/users" for 127.0.0.1 at 2017-02-22 09:22:11 -0800
Processing by Api::V1::RegistrationsController#create as */*
Parameters: {"user"=>{"email"=>"user#sampleapi.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "access_code"=>"uiux"}}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
Completed 400 Bad Request in 2ms (Views: 0.2ms | ActiveRecord: 0.4ms)
Updated Registrations_controller
class Api::V1::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
respond_to :json
def create
#user = build_resource(sign_up_params)
if #user.persisted?
# We know that the user has been persisted to the database, so now we can create our empty profile
if resource.active_for_authentication?
sign_up(:user, #user)
render :json => {:user => #user}
else
expire_data_after_sign_in!
render :json => {:message => 'signed_up_but_#{#user.inactive_message}'}
end
else
if params[:user][:email].nil?
render :status => 400,
:json => {:message => 'User request must contain the user email.'}
return
elsif params[:user][:password].nil?
render :status => 400,
:json => {:message => 'User request must contain the user password.'}
return
end
if params[:user][:email]
duplicate_user = User.find_by_email(params[:email])
unless duplicate_user.nil?
render :status => 409,
:json => {:message => 'Duplicate email. A user already exists with that email address.'}
return
end
end
render :status => 400,
:json => {:message => resource.errors.full_messages}
end
end
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute, :first_name, :last_name, :access_code])
end
end
I'm pretty sure my main issue at this point is the format of my params, so any push in the right direction for this would be great. I did find this post but am finding it a little difficult to follow in terms of what got their API to work...
Here is 2 solution, choose one you like.
Override devise_parameter_sanitizer:
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super # Use the default one
end
end
end
Override sign_up_params:
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
Why?
If you go deeping to Devise ParameterSanitizer, the resource_name will be :api_v1_user, not just :user because of your routes:
namespace :api do
namespace :v1 do
devise_for :users, controllers: { registrations: 'api/v1/registrations' }
end
end
Error resource_name will cause sign_up_params always return empty hash {}
Why don't you try something like this:
user = User.create(sign_up_params)
if user.save
render status: 200, json: #controller_blablabla.to_json
else
render :status => 400,
:json => {:message => #user.errors.full_messages}
end
or even better. You might use something like tiddle gem to make session more secure:
respond_to :json
def create
user = User.create(sign_up_params)
if user.save
token = Tiddle.create_and_return_token(user, request)
render json: user.as_json(authentication_token: token, email:
user.email), status: :created
return
else
warden.custom_failure!
render json: user.errors, status: :unprocessable_entity
end
end
You might use httpie --form to make the request:
http --form POST :3000/users/sign_up Accept:'application/vnd.sign_up.v1+json' user[email]='he#llo.com' user[username]='hello' user[password]='123456789' user[password_confirmation]='123456789'
do not forget:
def sign_up_params
params.require(:user).permit(:username, :email, :password, :password_confirmation)
end
I don't know what i'm missing, let me know if i'm wrong or something is wrong and i did't realize!
Regards!
Why not use the simple_token_authentication gem ?
Extremely simple to setup:
# Gemfile
gem "simple_token_authentication"
bundle install
rails g migration AddTokenToUsers "authentication_token:string{30}:uniq"
rails db:migrate
# app/models/user.rb
class User < ApplicationRecord
acts_as_token_authenticatable
# [...]
end
In your routes:
# config/routes.rb
Rails.application.routes.draw do
# [...]
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :classrooms
resources :notifications
end
end
end
In your controllers:
# app/controllers/api/v1/classrooms_controller.rb
class Api::V1::ClassroomsController < Api::V1::BaseController
acts_as_token_authentication_handler_for User
# [...]
end
Example call using the RestClient gem:
url = "http://localhost:3000/api/v1/classrooms/"
params = {user_email: 'john#doe.com', user_token: '5yx-APbH2cmb11p69UiV'}
request = RestClient.get url, :params => params
For existing users who don't have a token:
user = User.find_by_email("john#doe.com")
user.save
user.reload.authentication_token

Devise Omniauth - setup & defining strategies

I tried asking this question - and didn't find any help.
http://stackoverflow.com/questions/33493369/rails-devise-omniauth-problems-with-setup
I gave up trying to solve the problem and made an entirely new app with nothing else in it so that I could try to reduce the scope for other errors interfering.
In my new app, I now get an error when I click on the new registration/new user link.
I have followed the rails casts tutorials (having tried about 20 others) to get this setup. 1.5 years in and I am still struggling.
The problem is with the way the strategies are defined in the controller. I have 4 strategies (twitter, Facebook, google and linkedin) and am I am currently getting a different error for each of them when I try clicking on the links to create a new registration with those accounts:
For Twitter:
Unknown action
The action 'twitter' could not be found for Users::AuthenticationsController
For Facebook:
Given URL is not permitted by the Application configuration: One or more of the given URLs is not permitted by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains.
This error is because I can't figure out Facebook's documentation. It shows how to use js to login with Facebook where I am trying to use gems in Rails. I'm not worried about this error. I think it has something to do with my website not being defined as local host, although I can't find anywhere to but a callback url in Facebook's developer console. My question doesn't relate to this problem, I'll find help to sort this out another time.
For LinkedIn:
Safari can’t open the page “https://www.linkedin.com/uas/oauth2/authorization?client_id=LINKEDIN_DEV_ID&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fusers%2Fauth%2Flinkedin%2Fcallback&response_type=code&scope=r_basicprofile+r_emailaddress&state=3fef961c10410464cd5b0ca49b25112ce53fb65f1a3c794f”.
The error is: “cannot decode raw data” (NSURLErrorDomain:-1015)
I have an oauth2 callback defined as:
http://localhost:3000/users/auth/linkedin/callback
I don't know what's broken here.
For Google:
translation missing: en.devise.authentications.user.failure
The new registrations view just refreshes when i click this link and an error message says the above. I don't know what's causing this error either.
Each of the errors is different.
I have a folder in my controllers folder called users. Inside that I have two controllers as follows:
Authentications controller:
class Users::AuthenticationsController < Devise::OmniauthCallbacksController
before_action :set_authentication, only: [:destroy]
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
#authentication.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
#authentication = current_user.authentications.find(params[:id])
end
end
Registrations controller:
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
# before_action :configure_permitted_parameters, if: :devise_controller?
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
def create
super
session[:omniauth] = nil unless #user.new_record?
end
# THIS IS A SUGGESTION FROM SITEPOINT TUTORIAL
# protected
# def configure_permitted_parameters
# devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
# end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
def build_resource(*args)
super
if session[:omniauth]
#user.apply_omniauth(session[:omniauth])
#user.valid?
end
end
end
User.rb has
devise
:omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ]
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
self.email = auth['extra']['raw_info']['email']
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
In my routes.rb I have:
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => "users/authentications"
# :omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'users/authentications#create'
get '/sign_out', :to => 'users/authentications#destroy'
In my omniauth.rb I have:
require 'omniauth-facebook'
require 'omniauth-google-oauth2'
require 'omniauth-twitter'
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_KEY'],
:scope => 'public_profile', info_fields: 'id,first_name,last_name,link,email',
:display => 'popup',
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV['YT_CLIENT_ID'], ENV['YT_CLIENT_SECRET'],
scope: 'profile', image_aspect_ratio: 'square', image_size: 48,
# {name: "google_login", approval_prompt: ''},
access_type: 'online'
#ENV["GOOGLE_APP_ID"], ENV["GOOGLE_APP_SECRET"]
# {
# :name => "google",
# :scope => "userinfo.email, userinfo.profile, plus.me, http://gdata.youtube.com",
# :prompt => "select_account",
# :image_aspect_ratio => "square",
# :image_size => 50
# }
end
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env == 'production'
key = ENV["LINKEDIN_PRODUCTION_KEY"]
secret = ENV["LINKEDIN_PRODUCTION_SECRET"]
else
key = "LINKEDIN_DEV_ID"
secret = "LINKEDIN_DEV_KEY"
end
provider :linkedin, key, secret,
:scope => "r_basicprofile r_emailaddress",
:field => ["id", "email-address", "first-name", "last-name" ],
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
end
In my new registration/session views, I have:
<% if devise_mapping.omniauthable? %>
<%= link_to icon('facebook', id: 'facebookauth'), user_omniauth_authorize_path(:facebook) %>
<%= link_to icon('google', id: 'googleauth'), user_omniauth_authorize_path(:google_oauth2) %>
<%= link_to icon('linkedin', id: 'linkedinauth'), user_omniauth_authorize_path(:linkedin) %>
<%= link_to icon('twitter', id: 'twitterauth'), user_omniauth_authorize_path(:twitter) %>
<% end %>
I think it has something to do with not having named strategies the authentications controller. In other tutorials, I have set up the following (now commented out of the controller because there is a method called apply_omniauth used now).
# def facebook
# # #user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
# # if #user.persisted?
# # # #user.send_admin_mail
# # # #user.send_user_welcome_mail
# # sign_in #user, :event => :authentication #this will throw if #user is not activated
# # if #user.profile
# # redirect_to profile_path(#user.profile)
# # else
# # redirect_to new_profile_path
# # end
# # # sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
# # # set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
# # else
# # session["devise.facebook_data"] = request.env["omniauth.auth"]
# # redirect_to root_path
# # end
# # end
# # def linkedin
# # #user = User.find_for_linkedin_oauth(request.env["omniauth.auth"])
# # if #user.persisted?
# # # #user.send_admin_mail
# # # #user.send_user_welcome_mail
# # sign_in #user, :event => :authentication
# # if #user.profile
# # redirect_to profile_path(#user.profile)
# # else
# # redirect_to new_profile_path
# # end
# # # set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
# # else
# # session["devise.linkedin_data"] = request.env["omniauth.auth"]
# # redirect_to root_path
# # end
# # end
# # def twitter
# # begin
# # #user = User.from_omniauth(request.env['omniauth.auth'])
# # session[:user_id] = #user.id
# # flash[:success] = "Welcome, #{#user.name}!"
# # rescue
# # flash[:warning] = "There was an error while trying to authenticate you..."
# # end
# # redirect_to new_profile_path #root_path
# # end
# # #
# def google_oauth2
# # You need to implement the method below in your model (e.g. app/models/user.rb)
# #user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
# if #user.persisted?
# sign_in #user, :event => :authentication #this will throw if #user is not activated
# if #user.profile
# redirect_to profile_path(#user.profile)
# flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
# else
# redirect_to new_profile_path
# end
# else
# session["devise.google_data"] = request.env["omniauth.auth"]
# redirect_to new_user_registration_url
# end
# end
Before I completely ditch the rails cast setup, is there a way I can point the current structure towards the named providers using the code I already have?
ANOTHER ATTEMPT:
So I ditched the RailsCast. I tried to follow this tutorial:
http://willschenk.com/setting-up-devise-with-twitter-and-facebook-and-other-omniauth-schemes-without-email-addresses/
I'm confused by the reference to adding a new 'class' called FormUser. I made a new model called form_user.rb and added the content as described. I'm using Rails 4. I don't know what atto-accessor means, but I have it in my file as demonstrated. I don't have a corresponding controller. I also don't have associations defined in my user model (which I think this belongs to).
Anyway, I have followed the setup and now get this error:
TypeError
superclass mismatch for class OmniauthCallbacksController
It's the same for each of the strategies defined in my app.
Has anyone seen this particular error & have any tips for how to resolve it?
The only difference between my setup and the tutorial is that in my controllers, I have a folder called users, in that, I have a registrations controller and an omniauth_callbacks controller. My routes have been adjusted to reflect this layer.
devise_for :users, class_name: 'FormUser',
:controllers => {
:registrations => "users/registrations",
# :omniauth_callbacks => "users/authentications"
:omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'users/authentications#create'
get '/authentications/sign_out', :to => 'users/authentications#destroy'
devise_scope :user do
get '/users/auth/:provider/upgrade' => 'users/omniauth_callbacks#upgrade', as: :user_omniauth_upgrade
get '/users/auth/:provider/setup', :to => 'users/omniauth_callbacks#setup'
end
If anyone else is tearing their hair out trying to figure this out - I don't have the answers for how to do it, but I do know that the Railscasts are so old they are not useful. There are several parts of the code above that no longer match the gem config. Following those tutorials will not help you. Over the past 1.5 years I've tried to follow at least 20 different tutorials and am yet to find one that I can get to work. Errors in the rails cast include the redirect (doesnt require reference to 'user' any more amongst many others. Give up if you're relying on the Rails Cast. I'd really appreciate if anyone has any insights into where to find a CURRENT tutorial.

Devise with Rails API - current_user

I am building an API in Rails and using Devise for Authentication. My front-end is an AngularJS app. I am able to log in and create a new session on the Rails end, but as soon as I try to access the current_user method in my UsersController it's nil. Am I missing something here?
Appreciate any help. Thanks
SessionsController:
class SessionsController < Devise::SessionsController
respond_to :json
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
render :status => 200,
:json => { :success => true,
:info => "Logged in",
:user => current_user
}
end......
UsersController:
class UsersController < ApplicationController
before_filter :authenticate_user!, :except => [:create, :show]
respond_to :json
def show
render :json => {:info => "Current User", :user => current_user}, :status => 200
end....
I had to define current_user and run a custom authentication filter in my API to get the information straight from warden. I got the information below from a conglomeration of a few places here and here and a lot of trial and error with a debugger.
before_filter :api_session_authenticate!
private
def current_user
warden.user
end
def warden
env['warden']
end
def api_session_authenticate!
return not_authorized unless authenticate
end
def authenticate
warden.athenticated?
end
def not_authenicated
#render error messages and 401 status
end

Devise sign_in for api causing RSpec test to fail

I'm building an API using Rails and Devise. My sessions controller inherits from the following base controller
api/base_controller.rb
module Api
class BaseController < ApplicationController
skip_before_filter :verify_authenticity_token
before_filter :authenticate_user_from_token!
respond_to :json
private
def authenticate_user_from_token!
user_token = params[:auth_token].presence
user = user_token && User.find_by_authentication_token(user_token)
if user
sign_in user, store: false
else
render :json => {:success => false, :message => "Error with your credentials", :status => 401}
end
end
end
end
My sessions controller's destroy action below:
api/sessions_controller.rb
before_filter :authenticate_user_from_token!, :except => [:create]
def destroy
current_user.reset_authentication_token
render :json => {
:success => true,
:status => 200
}
end
This works perfectly when testing the api via curl. But, I can't get my Rspec tests for the destroy action to pass. From Rspec the sign_in user call is failing, so the response is a redirect. I haven't had any success trying to stub the sign_in method.
Rspec test:
describe "DELETE destroy" do
before(:each) do
#user1 = User.create!(:email => 'example#gmail.com', :password => 'helloworld', :password_confirmation => 'helloworld')
end
it "should render success json" do
delete :destroy, :auth_token => #user1.authentication_token
json = JSON.parse(response.body)
json.should include('success' => true, 'status' => 200)
end
###this fails because the response is a redirect to the sign_in page
end
How should I go about mocking the sign_in method called from within the base controller?
Add a spec/support/devise.rb file with this content:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Also, check in your test.log wether it's actually using the json format. I had a similar problem and found out that I had to force the format :json in my spec call parameters.
Andreamazz pointed me to the test.logs which revealed that the user I had created was confirmed (I'm using Devise confirmable). I use user.confirm! in the before(:each) and everything is passing.
describe "DELETE destroy" do
before(:each) do
#user1 = User.create!(:email => 'example#gmail.com', :password => 'helloworld', :password_confirmation => 'helloworld')
#user1.confirm!
end
it "should render success json" do
delete :destroy, :auth_token => #user1.authentication_token
json = JSON.parse(response.body)
json.should include('success' => true, 'status' => 200)
end
end
Thanks!

Omniauth + Devise Redirect Error

I have the following problem: My app is running as a Facebook app, but on the first time that the user accept's it's Facebook permissions, it's redirected to the right URL, but outside the Facebook (canvas). How can I fix it?
Here is my actual settings:
devise.rb:config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET'], scope: "email,publish_stream"
app/controllers/omniauth_callback_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def passthru
render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
end
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to root_path
end
end
def after_sign_in_path_for(resource)
inicio_path
end
end
routes.rb
Pl::Application.routes.draw do
ActiveAdmin.routes(self)
mount Resque::Server, :at => "/resque"
devise_for :admin_users, ActiveAdmin::Devise.config
devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks" }
devise_scope :user do
get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
end
match 'states' => 'game_plays#states'
match 'cities' => 'game_plays#cities'
match 'parties' => 'game_plays#parties'
match 'prefeito' => 'game_plays#prefeito'
match 'prefeitos' => 'game_plays#prefeitos'
match 'vereadores' => 'game_plays#vereadores'
match 'parties' => 'game_plays#parties'
match 'qualities' => 'game_plays#qualities'
match 'start' => 'game_plays#start'
match 'generated_image' => 'game_plays#generated_image'
match 'save_game_play' => 'game_plays#save_game_play'
match 'final' => 'game_plays#final', :as => :final
match 'inicio' => 'game_plays#index'
root :to => 'game_plays#bem_vindo'
end
Any sugestions?
This is from my own experience a couple months ago with this issue and I hope it helps.
From Facebook's point of view, this is exactly what it is suppose to do. It does not recognize the difference between where the request is coming from. You have to change the redirect URL on the request for it to stay in the iframe.
The easiest way I found to do this was to have the iframe url go to my_website.com/fb-app, which sets a session variable to let you know you are in the canvas and ensures they are already logged in through facebook. It then redirects them to the canvas site where the site continues as normal and the user never notices anything.
def fbapp
session[:fbapp] = true
if user_signed_in? == false
redirect_to user_omniauth_authorize_path(:facebook)
else
redirect_to $APP_CANVAS_URL + "?auth_token=" + current_user.authentication_token
end
end
Then, in your Application_controller.rb you need to change the redirect path. This is what it looked like in my application, note $APP_CANVAS_URL should be something along the lines of https://apps.facebook.com/your_app_here
def after_sign_in_path_for(resource_or_scope)
if session[:fbapp] == true
$APP_CANVAS_URL + "?auth_token=" + current_user.authentication_token
else
root_path
end
end
I doubt this is the best way, but it's what I got to work for me after hours of frustration. I hope it helps.

Resources