I am trying to implement both devise_token_auth and Active Admin in my rails api back-end.
There are pretty clear instructions on the devise_token_auth FAQ explaining how to implement the two together - it requires two different Application Controller classes.
# app/controllers/api_controller.rb
# API routes extend from this controller
class ApiController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
end
# app/controllers/application_controller.rb
# leave this for ActiveAdmin, and any other non-api routes
class ApplicationController < ActionController::Base
end
I have both of these controllers in my app, but I can't figure out how to inherit from them for the controllers for Active Admin and devise_token_auth.
I'm sure I am missing something basic here, because in all of the answers that I've seen about this on StackOverflow, it seems assumed that I know how to do this.
Can anyone help?
Edit:
Restating the problem, because I don't think I was clear the first time. Right now, both Active Admin and devise_token_auth are using the ApplicationController, even though I created the ApiController too. How do I make devise_token_auth use the ApiController?
You can definitely use a separate namespace, that will make your code cleaner and better organized. However it is not mandatory. All you need to do is in your controllers for the APIs, extend your ApiController instead of ActionController::Base.
For example, here's a base API controller,
class Api::V1::BaseController < ActionController::API
include DeviseTokenAuth::Concerns::SetUserByToken
include Pundit
end
and a sample controller that extends it and uses devise_token_auth as a result.
class Api::V1::SampleController < Api::V1::BaseController
def index
render json: { success: true, email: current_user.email }, status: :ok
end
end
Here's a sample project that has separate web and API controllers https://github.com/anujmiddha/rails-api-web-sample
you can refer to devise_token_auth demo example in devise_token_auth's readme on github.
the main difference between your case and the demo app is that you will use ApiController instead of ApplicationController. also, you have to add devise_token_auth attributes to the corresponding model, (for example, if you want to use devise_token_auth with users, you have to add the attributes to the users table and before_action: authenticate_user! to UsersController.).
Related
I am using rails 4, devise for authentication and Pundit for authorization. I have restricted my application to check for authorization on every controller by below code.
class ApplicationController < ActionController::Base
include Pundit
after_action :verify_authorized
#.....
end
However, i want to skip authorization for two specific controllers in my application (they are open to public, users do not need to sign in). How can i achieve it without removing verify_authorized in ApplicationController ?
skip_after_action :verify_authorized
I'm working with Rails 5 and I wanted to skip authorization in just one action but not the whole controller. So, what you can do according to the documentation is to use skip_authorization feature in the controller action as shown below:
class Admin::DashboardController < Admin::BaseController
def index
#organizers = Organizer.count
#sponsors = Sponsor.count
#brochures = Brochure.count
skip_authorization
end
def sponsors_approve
# some statements...
end
def organizers_approve
# some statements...
end
end
In this controller the only one action to be skipped is index, the other ones must be authorized.
I hope it could be useful for somebody else.
I have some Ruby methods certain (or all) controllers need. I tried putting them in /app/helpers/application_helper.rb. I've used that for methods to be used in views. But controllers don't see those methods. Is there another place I should put them or do I need to access those helper methods differently?
Using latest stable Rails.
You should define the method inside ApplicationController.
For Rails 4 onwards, concerns are the way to go. There was a decent article which can still be viewed via the Wayback Machine.
In essence, if you look in your controllers folder you should see a concerns sub-folder. Create a module in there along these lines
module EventsHelper
def do_something
end
end
Then, in the controller just include it
class BadgeController < ApplicationController
include EventsHelper
...
end
you should define methods inside application controller, if you have few methods then you can do as follow
class ApplicationController < ActionController::Base
helper_method :first_method
helper_method :second_method
def first_method
... #your code
end
def second_method
... #your code
end
end
You can also include helper files as follow
class YourController < ApplicationController
include OneHelper
include TwoHelper
end
You can call any helper methods from a controller using the view_context, e.g.
view_context.my_helper_method
Ryan Bigg response is good.
Other possible solution is add helpers to your controller:
class YourController < ApplicationController
include OneHelper
include TwoHelper
end
Best Regards!
Including helpers in controller will end-up exposing helper methods as actions!
# With new rails (>= 5)
helpers.my_helper_method
# For console
helper.my_helper_method
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.
I am attempting to use active admin with a project. This project also uses another gem to separate out different tenants, as well as has_secure_password for normal authentication.
I am having an issue skipping both of these filters when the user goes to active admin (just a different namespace - admin).
class ApplicationController < ActionController::Base
force_ssl
helper :all
protect_from_forgery
set_current_tenant_by_subdomain(:account, :subdomain) # need to skip this call when in the admin namespace
before_filter :require_user # need to skip this call when in the admin namespace
end
Thanks for your help!
You could create a BaseController that includes set_current_tenant_by_subdomain and before_filter :require_user and have your non-admin controllers inherit from that, while your admin controller inherits directly from the ApplicationController. That's worked for me in the past.
in config/initializers/active_admin.rb you can add the line:
config.skip_before_filter :offending_filter
sadly this does everything except the dashboard controller... for that you need
controller do
skip_before_filter :offending_filter
end
in app/admin/dashboard.rb
A have a bunch of controllers with the Admin namespace. I want to restrict access to these unless the user is an admin. Is there a way to do this using CanCan without having to call unauthorized! in every method of every controller?
Add an application controller to your namespace and a before filter to it.
class ApplicationController < ActionController::Base
end
class Admin::ApplicationController < ApplicationController
# these goes in your namespace admin folder
before_filter :check_authorized
def check_authorized
redirect_to root_path unless can? :admin, :all
end
end
class SomeadminController < Admin::ApplicationController
def some_action
# do_stuff
end
end
The Admin Namespaces wiki page for CanCan lists out several solutions to this problem.
As #mark suggested, have a base controller for admins which checks authorization for every action.
You may not need to use CanCan at all for this if all you require is to check that users have an admin
flag.
For handling admins differently from each other (as opposed to differently from regular users only),
consider a separate AdminAbility class (this is a little off-topic, but could prove relevant).
now rails_admin has full support with Cancan, you can find it in its official website, there is a wiki page for this topic:
Rails Admin's authorization with CanCan: