I started using comatose to handle content on my site but am having problems using it with my existing authentication using a generic Authlogic config.
In the readme he sites an example for configuring it with Restful Authentication and I'm wondering how I would do the same within a general Authlogic setup?
#environment.rb
Comatose.configure do |config|
# Includes AuthenticationSystem in the ComatoseController
config.includes << :authenticated_system
end
http://github.com/darthapo/comatose
I think a better way to do it is moving the auth methods out into a module, and include that from both ApplicationController and comatose. Example:
Put your auth methods into user_sessions_helper:
module UserSessionsHelper
module AuthMethods
private
...
def require_user
...
Then include the module in your ApplicationController:
class ApplicationController < ActionController::Base
include UserSessionsHelper::AuthMethods
...
And finally in the comatose config as well (environment.rb):
Comatose.configure do |config|
config.admin_includes << "UserSessionsHelper::AuthMethods"
config.admin_authorization = :require_user
end
Related
There are 3 ways to get in my applications with an invite token:
You're already logged in
You have an account, but not logged in
You need to register
Now I'm interested how to handle the last 2 situations in combination with Devise without having to repeat the same functions.
Controller overrides are handled from the routes.rb:
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
Overriding the after_sign_in/up_path for Sessions and Regitrations:
class Users::SessionsController < Devise::SessionsController
protected
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
handle_invite
super(resource)
end
end
Where should I place the handle_invite method?
I'm looking for a solution that I can put the method in my UsersController, because that seems to be the right place to put it.:
class UsersController < ApplicationController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
I thought this should work, because it seems that Devise inherits this controller:
class Users::SessionsController < Devise::SessionsController; end
class Devise::SessionsController < DeviseController; end
class DeviseController < Devise.parent_controller.constantize; end
So I expected Devise.parent_controller.constantize to represent UsersController, but for some reason handle_invite can't be called from the child controllers.
If you want to use classical inheritance you would have to actually place that class in the inheritance chain by configuring Devise.parent_controller while not breaking the rest of the chain.
Ruby does not have multiple inheritance. A class may only inherit from a single parent class.
# config/initializers/devise.rb
config.parent_controller = 'UsersController'
class UsersController < DeviseController
private
def handle_invite
# Some code getting the token and adding the user to a group
end
end
But that's not really the best way to solve it since Ruby has horizontal inheritance through modules:
# app/controllers/concerns/invitable.rb
module Invitable
private
def handle_invite
# Some code getting the token and adding the user to a group
end
def after_sign_in_path(resource)
handle_invite
super(resource)
end
end
# Do not use the scope resolution operator (::) for namespace definition!
# See https://github.com/rubocop-hq/ruby-style-guide#namespace-definition
module Users
class SessionsController < ::Devise::SessionsController
include Invitable
end
end
module Users
class RegistrationsController < ::Devise::SessionsController
include Invitable
end
end
This is known as a module mixin. In other languages like Java or PHP it would be called a trait. The module encapsulates a set of methods that can be included in any class and you can also mix modules into other modules.
In Rails lingo module mixins are called concerns - this really just wraps a convention that the app/controllers/concerns and app/models/concerns directories are added to the autoload roots. Which means that rails will look for constants in the top level namespace there.
This is also loosely connected to ActiveSupport::Concern which is syntactic sugar for common ruby idioms. But there is no need to use it unless you're actually using its features.
I have authentication service using
Json Web Token
in my Rails API.
I want to check if Token is valid in every request my API gets.
Problem is that when i write function which checks if Token is valid in main
application_controller.rb
file it is not visible in engines and i can't do before_action for every engine i have. is there any way to validate Token in every request my application gets in every engine?
You can create a .rb file under config/initializers
class ActionController::Base
before_action :validate_jwt_token
def validate_jwt_token
# validate jwt token
end
end
This will make sure validate_jwt_token is executed on every request among all of the mounted engines.
Edit:
You can also put this code under Api engine or Umg's engine.rb
module Api
class Engine < ::Rails::Engine
#...
initializer 'api.jwt_token_validation_helper' do
ActionController::Base.send :include, Api::JwtTokenValidationHelper
end
end
end
module Api
module JwtTokenValidationHelper
extend ActiveSupport::Concern
include do
before_action :validate_jwt_token
def validate_jwt_token
puts 'your code here'
end
end
end
end
I want to add a filter to the ApplicationController but I want to do it within my gem.
What I want to avoid is the following:
class ApplicationController < ActionController::Base
include MyGem
end
I do not want that. I don't want to have to include my module in the source code.
I am having issues though.
Here is the relevant code:
lib/correlation_id/controller_extension
module CorrelationId
module ControllerExtension
def self.included(klass)
klass.class_eval do
after_filter :pass_correlation_id
end
end
def pass_correlation_id
correlation_id = request.headers['Correlation-ID'] || SecureRandom.uuid
headers['Correlation-ID'] = correlation_id
end
end
end
ApplicationController.send :include, CorrelationId::ControllerExtension
lib/correlation_id.rb
require 'correlation_id/controller_extension'
module CorrelationId
end
Now, when I'm in the test/dummy directory, which is a test rails app for my gem, I try to boot up the server using rails s and I get the following error:
/correlation_id/lib/correlation_id/controller_extension.rb:17:in `<top (required)>': uninitialized constant ApplicationController (NameError)
I'm clearly having problems with referencing ApplicationController to monkey-patch it.
How would I manage this? I want my gem to be self-contained.
The following code works. What I did was prematurely create ApplicationController with the appropriate inheritance. Note, many people use the rails-api gem, so I factored in them to ensure the fact that it would work.
Also, note: You must inherit from a class because otherwise ApplicationController will be a usual class that doesn't understand what after_filter is.
module CorrelationId
module ControllerExtension
def self.included(klass)
klass.class_eval do
after_filter :pass_correlation_id
end
end
def pass_correlation_id
correlation_id = request.headers['Correlation-ID'] || SecureRandom.uuid
headers['Correlation-ID'] = correlation_id
end
def self.base_controller_inheritance
if Gem::Specification.find_all_by_name('rails-api').any?
ActionController::API
else
ActionController::Base
end
end
end
end
class ApplicationController < CorrelationId::ControllerExtension.base_controller_inheritance
include CorrelationId::ControllerExtension
end
I imagine there might be a better way to check if they are using ActionController::API and if so, please do share, but as of now, this seems like the most solid way to do it.
I have a custom module in my lib directory that I load in my Application controller. I started using cancan and now I am getting Access Denied error for all the actions in my custom module. I don't want cancan to check authorization on my custom module. One way to get around this is to use except => [:action_name_in_my_custom_module] but I have lot of actions that I use in my application at many places. I need a better solution.
Assuming you have a module of controller actions and you are including it in your controllers, is there a reason you didn't put them all in ApplicationController?
One thing you can try is using skip_before_filter in the module. This will call the method on any class in which you include MyModule:
module MyModule
def self.included(klass)
klass.class_eval <<-filters
skip_before_filter :filter_method_to_skip, only: [:method_a, :method_b, ...]
filters
end
end
class MyController < ApplicationController
before_filter :filter_method
include MyModule
end
I believe it needs to be included after your before filters are defined.
Strange thing – I have Authentication module in lib/ like this:
module Authentication
protected
def current_user
User.find(1)
end
end
and in ApplicationController I'm including this module and all helpers, but method current_user is available in controllers, but not from views :( How can I make this work?
If the method were defined directly in the controller, you'd have to make it available to views by calling helper_method :method_name.
class ApplicationController < ActionController::Base
def current_user
# ...
end
helper_method :current_user
end
With a module, you can do the same, but it's a bit more tricky.
module Authentication
def current_user
# ...
end
def self.included m
return unless m < ActionController::Base
m.helper_method :current_user # , :any_other_helper_methods
end
end
class ApplicationController < ActionController::Base
include Authentication
end
Ah, yes, if your module is meant to be strictly a helper module, you can do as Lichtamberg said. But then again, you could just name it AuthenticationHelper and put it in the app/helpers folder.
Although, by my own experience with authentication code, you will want to have it be available to both the controller and views. Because generally you'll handle authorization in the controller. Helpers are exclusively available to the view. (I believe them to be originally intended as shorthands for complex html constructs.)
Did you declare it with
helper :foo # => requires 'foo_helper' and includes FooHelper
helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
in your ApplicationController?
http://railsapi.com/doc/rails-v2.3.3.1/classes/ActionController/Helpers/ClassMethods.html#M001904