Devise Signout in Rails API call - ruby-on-rails-3

I am working on rails 3.2 and using jquery mobile and handlebar for mobile application. I am trying to write logout functionality using API call.
in my lib/extras/api/users.rb
i am trying to do logout functionality of devise.
How to write
For now i wrote like
resource :users do
delete '/sign_out' do
authenticate!
user = User.find(params[:id]) rescue not_found
# What to write here to signout the user
end
end

You can use Warden (Devise uses it for authentication) to log the user out by first specifying a helper method which will give you the warden object:
def warden
env['warden']
end
and then from the api you can access the helper and apply the following method on it in order to log out the user:
warden.logout

Related

rails administrate with cancancan

Im using rails administrate for my application, but I want to limit access via the administrate dashboard to the resources being administered.
Im also using cancancan in the other parts of my rails app to manage access and permissions.
Has anyone managed to use cancancan within administrate, so that the administrate dashboard can use the abilities defined in cancancan, do display the resources and apply the same persmissions ?
Thanks
You can find some info about what needs to be done here: https://administrate-prototype.herokuapp.com/authorization
What is mentioned there works well for filtering collections of records, but breaks when trying to authorize individual resources. The solution is to override the find_resource method. Here is the final working code:
# app/controllers/admin/application_controller.rb
rescue_from CanCan::AccessDenied do |exception|
flash[:notice] = "Access Denied"
redirect_to admin_root_path
end
# Override find_resource, because it initially calls scoped_resource.find(param)
# which breaks since we are overriding that method as well.
def find_resource(param)
resource_class.default_scoped.find(param)
end
# Limit the scope of the given resource
def scoped_resource
super.accessible_by(current_ability)
end
# Raise an exception if the user is not permitted to access this resource
def authorize_resource(resource)
raise CanCan::AccessDenied unless show_action?(params[:action], resource)
end
# Hide links to actions if the user is not allowed to do them
def show_action?(action, resource)
# translate :show action to :read for cancan
if ["show", :show].include?(action)
action = :read
end
can? action, resource
end
This will get you started for basic resource authorization with CanCan. Further customization of field views might be needed if you need to restrict access to nested resources etc. But that should be pretty standard from that point forward. Hope this helps. :)

Roll your own authentication with the rails_admin gem stops working with rails 5

This SO answer shows how to authenticate the rails_admin gem when you have a roll your own authentication. The method follows this pattern. However, this solution no longer works with rails 5. Instead, when trying to access an admin view, the following exception is triggered in config/initializers/rails_admin.rb
undefined method `signed_in?' for #<RailsAdmin::MainController:0x007fbe38628ab0>
How do you fix this?
The usual view helpers, like signed_in? or current_user are no longer accessible in the initializer, so the solution that I came up with was:
config.authenticate_with do
current_user = User.find_by_id(session[:user_id])
raise 'You must be admin' unless current_user.try(:admin?)
end

Fetch Google plus contacts in Rails app

I have google login feature implemented in my Rails app and now the scenario is to fetch google plus contacts in my app.
There is one Google Plus gem available but i am not sure whether i can fullfill my requirements using that gem.
Whats the best possible solution to this.
Regards,
Karan
You can use the Google APIs Ruby Client and do something like:
client = Google::APIClient.new
plus = client.discovered_api('plus')
# Code to authorize the client.
...
result = client.execute(plus.people.list,
:collection => 'visible',
:userId => 'me')
Where the code that you need to authorize the client depends on the flow that you are using to implement the login.
I've encounter the same situation, nowhere was clear answer.
What gem you are using for Google Authorization? If you are using omniauth-google-oauth2 here is the solution:
I've found post of a guy who encounter different problem AFTER part of application you are asking for was done, you may find it here - http://blog.baugues.com/google-calendar-api-oauth2-and-ruby-on-rails
Down to the code, this how you callback function in a controller (after logging in) should looks like:
def create #lets say it is session#new controller
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
initial_session(omniauth) unless current_user
client = Google::APIClient.new()
client.authorization.access_token = omniauth["credentials"]["token"]
plus = client.discovered_api('plus')
contacts = client.execute(plus.people.list, :collection => 'visible',
:userId => 'me')
raise contacts.inspect.to_s

Rails 3 and Devise: authenticating a user while performing a POST action

Using Rails 3.0.6, Omniauth 0.2.0 and Devise 1.2.1, I'm encountering the following situation:
I want to offer users the option to authenticate via Facebook. I have a user system set up using Devise and I can successfully auth using Facebook. I've spent several hours trying to code the behavior I want for one specific situation:
user is not logged in
user has a site account
user authenticates via Facebook
I offer the user 2 choices at this point
create an account (can be a dummy account with no provided info)
link this Facebook authentication with an existing account
I'm having trouble with the latter option. The user has already authenticated but I still need him to log in with his site account. I have an action in my AuthenticationsController that will associate this authentication with a logged in user. Devise doesn't seem to offer a way for me to log the user in while staying in the same action, though. This was my first attempt to do this
class AuthenticationsController < ApplicationController
before_filter :authenticate_user!, :only => :auth_link_existing_user
...
def auth_link_existing_user
...
end
However, using this method, if the user logs in, they're simply redirected to my site's root page. I know I can change Devise's sign-in redirect, but that will be for all sign-ins. I wanted only this situation to have a separate redirect.
After reading through this mailing list question, I tried to extend SessionsController with my own custom behavior:
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
if params[:redirect] #new
redirect_to params[:redirect].to_sym #new
else
respond_with resource, :location => redirect_location(resource_name, resource)
end
end
This doesn't work either. I've defined my auth_link_existing_user route to use a POST verb (which seems accurate) and redirects can only be GETs.
So now I do have a solution in mind: copy and paste code from Devise's authenticate_user! helper into a new function which can be called within a controller action without redirecting. This seems less than ideal to me because it's duplication of code and increases coupling--a Devise or Warden update that changes this behavior will break my code as well.
Has anyone else tried something like this and come up with a more elegant solution? Do you see a simpler way for me to offer this or similar behavior to my users?
UPDATE: For anyone who wants to use my dirty solution at the end, this is what I did:
def auth_link_existing_user
# FROM Devise/sessions/create
resource = warden.authenticate!(:scope => :user, :recall => "registrations#auth_new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(:user, resource)
# method defined in Ryan Bates' Railscast for Omniauth w/Devise
current_user.apply_omniauth(session[:omniauth])
current_user.save
end
note that this action MUST be placed in your sessions controller. If not, Warden will give you an "invalid email/password" error. It was an incredibly long debugging process to find the source.
With this in place, I use a login form to submit to this action after the user has authenticated.
I like how clean your solution is, though it goes deeper into the stack.
Here is how I've implemented something similar by following the Devise+Omniauth Facebook example on the Devise wiki and modifying the facebook method to pass on the session information to the Login form, with something like this:
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 new_user_session_url
end
Then, in your case, I'd check in Login controller action for session["devise.facebook_data"], submit the uid + token with the form and apply_omniauth if present.

Mocks aren't working with RSpec and Devise

I'm working on a Rails 3 web app at the moment with RSpec 2 and we're using Devise for authentication. One (and soon many) of our controllers require the user to be logged in. I know Devise provides the sign_in test helper, but can it be used with an RSpec or Mocha mock object?
I originally tried #user = mock_model(User) where user is the Devise class. This wouldn't work with sign_in :user, #user as get 'index' would redirect to the sign in form.
Does anyone have any experience testing with Devise and can help?
We had a similar problem, but using Factory Girl. We solved it like so:
In spec_helper.rb:
config.include Devise::TestHelpers, :type => :controller
In the controller spec (just a wrapper method):
def login_user(user)
sign_in user
end
Then in each method you require, you can do:
login_user(Factory(:user))
... where you have defined a user object in factories.rb. Not sure if this will work with mocks though.
A mock is never going to work. When you say sign in, the user is stored in session (basically, the user class and its id). When you access the controller, another user object is retrieved based on the stored data. The best way to solve the problem is using something that persists the object, like Factory Girl.
I hit the same issue. I'm doing the following for now:
before(:each) do
# sign_in mock_user
request.env['warden'] = mock(Warden, :authenticate => mock_user,
:authenticate! => mock_user)
end
I've created an issue for this here: https://github.com/plataformatec/devise/issues#issue/928
Go vote!
None of them worked for me (MRI 1.9.3-preview1, rails 3.0.1.rc5).
this is the solution i found : http://blog.joshmcarthur.com/post/6407481655/integration-tests-with-devise-and-rspec