Get access to current_user in Doorkeeper overriden layout - ruby-on-rails

Since Doorkeeper is an isolated Engine we have no access to whatever you did in ApplicationController. But what if you need a current_user? What could be a workaround here?
The first idea is to monkey-patch ActionController::Base. Any better thoughts?

My doorkeeper implementation was inside of the base app so this wont help if you are using a separate engine but will if you use the same rails app so I will share here:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
if doorkeeper_token
return current_resource_owner
end
# fallback to auth with warden if no doorkeeper token
warden.authenticate(:scope => :user)
end
# Needed for doorkeeper find the user that owns the access token
def current_resource_owner
User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
end
end

Unless there are no answers, may be my own dirty monkey patch will be useful to someone.
in initializers/action_controller_patch.rb:
module ActionController
Base.class_eval do
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
end
end

I think you can find it on this page.
https://github.com/applicake/doorkeeper/wiki/Using-Resource-Owner-Password-Credentials-flow
I am using credential auth pattern, so in my case this works.
Doorkeeper.configure do
resource_owner_from_credentials do |routes|
request.params[:user] = {:email => request.params[:username], :password => request.params[:password]}
request.env["devise.allow_params_authentication"] = true
request.env["warden"].authenticate!(:scope => :user)
end
end

Related

Get root_url in a Rails service

The app I'm working on makes heavy use of Rails services. My problem is I need to get the root url of the app, similar to how you would use root_url in a view, but this doesn't work in a service. Does anyone know a way to do this other than entering the url in each of my environment setting files?
Edit
I tried using Rails.application.routes.url_helpers.root_url as it suggests to do here stackoverflow.com/a/5456103/772309 but it expects you to pass the :host => ... in as a parameter. That's what Im trying to find.
Based on what I've read from the linked 'Rails services' article, the services are just plain old ruby objects. If that's the case, then you'd need to pass the root_url from the controller to the initializer of your service object. To extend the example from that article:
UsersController
class UsersController < ActionController::Base
...
private
...
def register_with_credit_card_service
CreditCardService.new({
card: params[:stripe_token],
email: params[:user][:email],
root_url: root_url
}).create_customer
end
end
CreditCardService
class CreditCardService
def initialize(params)
...
#root_url = params[:root_url]
end
end
EDIT: Alternative solution that leverages the Rails.application.config
class UsersController < ActionController::Base
before_filter :set_root_url
def set_root_url
Rails.application.config.root_url = root_url
end
end
class CreditCardService
def some_method
callback_url = "#{Rails.application.config.root_url}/my_callback"
end
end
Since you're opposed to putting it in your environment folders you could do something like below in your App controller
class ApplicationController < ActionController::Base
def default_url_options
if Rails.env.production?
{:host => "myproduction.com"}
else
{}
end
end
end

Implementation of survey using surveyor gem in rails

I am trying to implement a survey using the surveyor gem in rails. I want to make use of the user id to keep track of which user creates the survey and which user gave what response on which survey.
The problem is that I did not use the Devise gem for my user signin and signup. I built it manually. The surveyor gem uses a helper method current_user of Devise which returns details about the current user.
Since, I did not use devise, I am not sure where to add the helper method current_user.
I am not really sure as to what code to post, so please comment the required details. I will edit my post as needed.
Thanks!
application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :authorize
helper_method :current_user
protected
def authorize
return true if ((self.class == SessionsController)|| (self.class == UsersController && (self.action_name == "new" || self.action_name == "create")))
unless (User.find_by_id(session[:user_id]))
redirect_to url_for(:controller => :sessions , :action => :new), alert: "You need to be logged in."
end
end
def current_user
#current_user = User.find(session[:user_id])
end
end
Here is the link of the surveyor gem controller which uses the current_user method: https://github.com/kjayma/surveyor_gui/blob/master/app/controllers/surveyor_gui/survey_controller.rb
Here is one possible solution to implement a current_user method.
helper_method would make the current_user method available in every controller, which inherits from ApplicationController.
class ApplicationController
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end

Converting Mongoid to ActiveRecord for Devise-Basecamp setup

I am setting up Devise-Basecamper to enable subdomain scoped authentication to extend Devise's usefulness even more. The gem might be a bit old but it seems like an ideal solution if I get everything up and running. The README.md is super clear but the only thing that threw me off is a bit of code relating to Mongoid even though I am using ActiveRecord. If you could help me write this code according to ActiveRecord I would be very grateful. I have a model called Account, which is like the company or organization.
Here's the necessary excerpt from Devise-Basecamper's readme. I have put the Mongoid code in >>> and <<<
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :subdomain, :current_account
before_filter :validate_subdomain, :authenticate_user!
private # ----------------------------------------------------
def current_acount
# The where clause is assuming you are using Mongoid, change appropriately
# for ActiveRecord or a different supported ORM.
>>>#current_account ||= Association.where(subdomain: subdomain).first<<<
end
def subdomain
request.subdomain
end
# This will redirect the user to your 404 page if the account can not be found
# based on the subdomain. You can change this to whatever best fits your
# application.
def validate_subdomain
redirect_to '/404.html' if current_account.nil?
end
end
First of all, there is a typo in current_account method. It's current_account not current_acount.
so replace this line
def current_acount
with
def current_account
Second, You have change Association to Account because Account is actually Model.
Replace this line
#current_account ||= Association.where(subdomain: subdomain).first
with
#current_account ||= Account.where(subdomain: subdomain).first
Third, If you're not using mongoid then you have change where clause. e.g.
replace where clause
#current_account ||= Association.where(subdomain: subdomain).first
with
#current_account ||= Association.where("subdomain = ?", subdomain).first
Final code is here..
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :subdomain, :current_account
before_filter :validate_subdomain, :authenticate_user!
private # ----------------------------------------------------
def current_account
# The where clause is assuming you are using Mongoid, change appropriately
# for ActiveRecord or a different supported ORM.
#current_account ||= Account.where("subdomain = ?", subdomain).first
end
def subdomain
request.subdomain
end
# This will redirect the user to your 404 page if the account can not be found
# based on the subdomain. You can change this to whatever best fits your
# application.
def validate_subdomain
redirect_to '/404.html' if current_account.nil?
end
end

Helper methods are not being seen (Rails 4 engine)

I have defined a helper method as such (for my rails engine):
module Xaaron
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
helper_method :current_user
helper_method :authenticate_user!
def current_user
#current_user ||= Xaaron::User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end
def authenticate_user!
if current_user
true
else
redirect_to xaaron.login_path
false
end
end
protected
def record_not_found
flash[:error] = 'Could not find specified role'
redirect_to xaaron.record_not_found_path
true
end
end
end
As far as I know everything above is correct in terms of creating helper methods. So now I need to use this helper method:
module Xaaron
class ApiKeysController < ActionController::Base
before_action :authenticate_user!
def index
#api_key = Xaaron::ApiKey.where(:user_id => current_user.id)
end
def create
#api_key = Xaaron::ApiKey.new(:user_id => current_user.id, :api_key => SecureRandom.hex(16))
create_api_key(#api_key)
end
def destroy
Xaaron::ApiKey.find(params[:id]).destroy
flash[:notice] = 'Api Key has been deleted.'
redirect_to xarron.api_keys_path
end
end
end
As you can see, before every action the user must be authenticated. So the authenticat_user!
method is then called.
Lets write a test for this
it "should not create an api key for those not logged in" do
post :create
expect(response).to redirect_to xaaron.login_path
end
This, we expect, to send us back to the login path because we are not signed in, and as you will recall we are using authenticate before every action in the API Controller. What do we get instead:
1) Xaaron::ApiKeysController#create should not create an api key for those not logged in
Failure/Error: post :create
NoMethodError:
undefined method `authenticate_user!' for #<Xaaron::ApiKeysController:0x007f898e908a98>
# ./spec/controllers/api_keys_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
Last I checked the way I defined a helper method is how rails casts has done it, how other stack questions have done it and how rails docs states to do it - unless I missed some majour step - why isn't this working?
Maybe I haven't seen a helper method set up like this before (I'm new to rails) but the helper methods I've seen are defined without controllers.
Usually I see a file like this in the helpers folder
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def current_user=(user)
#current_user = user
end
...
and then
include SessionsHelper
In the application controller.
To me it looks like you're calling the controller a helper method, I'm not sure what the benefits of that would be - but I suppose I wouldn't.
Sorry if this wasn't helpful

Rails session timeout and redirect to sign in page

I would like to do rails session timeout and redirect to sign in page after session expire.
This is my application controller and seem not working.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_filter :session_expires, :only => [:login]
def session_expires
a = session[:expires_at]
b = Time.now
minutes = (a - b)/1.minute
if b > a
reset_session
flash[:error] = 'Session Expire !'
render "sessions/new"
end
end
end
I am not sure, I need to use Jquery or Ajax to make it work. Can anyone give me some idea or some good tutorial i can follow. Thank in million.
You want to run the before_filter on every request, not just login.
Replace before_filter :session_expires, :only => [:login] with before_filter :session_expires.
I suggest you take a look on this guide - why you shouldn't do authentication on your own
The definitive guide to form-based website authentication
There's an excellent solution for Ruby/Rails available - Devise gem https://github.com/plataformatec/devise
If you need to authenticate against some external api, take a looke here
https://github.com/plataformatec/devise/wiki/How-To:-Authenticate-via-LDAP
http://4trabes.com/2012/10/31/remote-authentication-with-devise/
I got following simple solution.
I added one simple method in application.rb. it worked well.
class ApplicationController < ActionController::Base
before_filter :session_expires
MAX_SESSION_TIME = 60 * 60
helper_method :current_user?
protected
def current_user?
if session[:user_id].nil?
false
else
true
end
end
def authorize
unless current_user?
flash[:error] = "Please Login to access this page !";
redirect_to root_url
false
end
end
def session_expires
if !session[:expire_at].nil? and session[:expire_at] < Time.now
reset_session
end
session[:expire_at] = MAX_SESSION_TIME.seconds.from_now
return true
end
protect_from_forgery
end

Resources