I'm trying to skip the authentication for a custom ActiveAdmin member action that I've created. Here's what I've been trying, but it still brings me to the login page.
ActiveAdmin.register Foo, as: "Foos" do
controller do
skip_before_action :authenticate_admin_user!, only: :bar
end
member_action :bar, method: :get do
# render something
end
end
Versions:
Rails: 4.1.1
ActiveAdmin: 1.0.0.pre1
Have a look at this gist.
Put the self.filters and self.before_filters methods into controller do block.
Add binding.pry after those methods and restart application server - this should stops on binding.
Type filters(:before) and you will see a list of callbacks.
Find the callback responsible for authentication, e.g. authenticate_active_admin_user.
Add skip_before_filter :authenticate_active_admin_user to controller do block.
Have a break :)
Related
I have a Rails 3.2.22 app running in production for +1 year which uses Devise to authenticate users.
I'm trying to implement token authentication, so I can send transactional e-mails with URL params that can log in the user automatically, using a Gem named Simple Token Authentication https://github.com/gonzalo-bulnes/simple_token_authentication
After following all the instructions, I replaced before_filter :authenticate_user! in my controllers with acts_as_token_authentication_handler_for User.
The gem has integration with and a default fallback to Devise, so devise doesn't need to be called in the controllers anymore; if the token is missing from the params (or wrong), Devise will take over.
In my tests, if I add this line to ApplicationController, everything works fine and I can log in users using the authentication_token= secret the gem generates.
But I don't need auth for ApplicationController, I need it for other controllers (like DashboardController), url being /dashboard
If I put acts_as_token_authentication_handler_for User in that controller (replacing Devise's call), I get the most bizarre of situations.
Using binding.pry, I can confirm that current_user is correctly set during the loading of the template.
But there comes a point in the template where it uses #last_emails, which is defined inside a method in ApplicationController.
Using binding.pry, I can confirm current_user is nil there.
This is the code:
class DashboardController < ApplicationController
layout 'material'
acts_as_token_authentication_handler_for User
And in ApplicationController:
class ApplicationController < ActionController::Base
layout 'omega'
before_filter :populate_last_contacts_for_menu
private
def populate_last_contacts_for_menu
if current_user
#last_contacts = Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
end
end
Funny thing is: using binding.pry, like I said, I can check that current_user is defined in the template (which means sign_in was a success). It even is defined in the better errors console. But, if I go to homepage, I see that user is not logged in ...
I've looked all over the web for this: read all the issues inside the Gem's github and all posts in SO about current_user being nil, but no light at all.
My devise_for :users is not inside any scope in routes.rb and, as I said, I have many calls to current_user all over the app and this is the first time I have issues with Devise.
When you call the acts_as_token_authentication_handler_for directive in the DashboardController it declares some before_filters for the controller to authenticate a user.
But the problem is that when you inherit rails controllers, at first, filters of a parent controller are executed, then filters of a child controller.
The parent controller is ApplicationController. At the moment when it's populate_last_contacts_for_menu filter is called, the user is not authentacated, because the authenticating filters given by the acts_as_token_authentication_handler_for directive have not called yet, they are declared in the child controller.
Possible solutions:
1) Try to append the populate_last_contacts_for_menu filter:
append_before_filter :populate_last_contacts_for_menu
I am not sure it will work in your case, but you can try and find it out.
2) Call the acts_as_token_authentication_handler_for directive in the ApplicationControoler and somehow skip it for the controllers that don't need it. (I don't like this way, but it may help if the first one will not work. )
3) Move the populate_last_contacts_for_menu filter logic into helpers. I think it is the best solution. This logic doesn't belong to a controller. When requests are not 'get', this filter executes for nothing, because you don't need to render views in that case.
module ApplicationHelper
def last_contacts
#last_contacts ||= if signed_in?
Contact.where("user_id" => current_user.id).where('blocked != ? or blocked is null', true).last(10).reverse
else
[]
end
end
...
end
# View:
<% if last_contacts.present? %>
....
<% end %>
I want to add a method called quick_view, which is basically a show method but much simpler and meant to be served with Ajax on hover on a product.
How can i achieve this ? How can i open the ProductsController of spree and add before_filters and also specify the appropriate routes..
Thanks !
Doco for that is at https://guides.spreecommerce.com/developer/logic.html
Create a class called app/controllers/products_controller_decorator.rb, and put something like this in it:
Spree::ProductsController.class_eval do
before_filter :my_filter, :only => :quick_view
def quick_view
# your code goes here
end
private
def my_filter
# code for your before filter goes here
end
end
As for the routes, you'll be able to add it in your routes.rb file just like any other route, but you'll need to specify that it's a spree route:
Spree::Core::Engine.routes.draw do
# Your route goes inside this block
end
Can you have non-restful methods in a controller which includes the WickedWizard gem?
Controller:
class Books::BookUpdateController < ApplicationController
include Wicked::Wizard
steps :title_step, :ai_archive_step, :ai_override_step #etc
def show
...
end
def update
...
end
def waterfall
...# loads of code to set up instance variables in the view, which I don't want to have to include in the normal show action for all the wizard steps.
end
end
Routes:
resources :book_update do
member do
get 'waterfall'
... and others
end
end
Version 1 and lower of the gem allows non restful actions, but this commit to solve this PR enforces step names. My error on going to this route http://localhost:3000/book_update/3949/waterfall is
Wicked::Wizard::InvalidStepError in Books::BookUpdateController#waterfall
The requested step did not match any steps defined for this controller.
I suppose I should spark up a new controller and tuck the non restful actions into there, but alternatives would be great.
You need to add:
skip_before_filter :setup_wizard, only: :waterfall
in your wicked controller
How can i set routes for controller defined in active_admin gem.
In active_admin, links.rb i have:
controller do
def admin_links
//some code
end
end
and then i try to do routes for it:
scope '/admin_links' do
put...??
end
But i just dont know what controller should i call. Can anybody help?
controller do is meant to overwrite existing actions.
If you want to add actions, use either member_action or collection_action.
Doc is here.
since you use PUT verb, you'll have to do:
member_action :admin_links, method: 'put' do
# your action code here
end
I have CanCan and Rolify set up with ActiveAdmin, and now it's time to force authorization on my controllers.
Do I have to authorize_resource on every controller (We have a couple dozen models and controllers now), or is there a way to apply it to all of my ActiveAdmin controllers?
I tried calling it in a before_filter from ActiveAdmin.setup, but that didn't work.
I made an initializer: config/initializers/active_admin-cancan.rb
module ActiveAdmin
class ResourceController
# If you don't skip loading on #index you will get the exception:
#
# "Collection is not a paginated scope. Set collection.page(params[:page]).per(10) before calling :paginated_collection."
load_resource :except => :index
authorize_resource
def scoped_collection
end_of_association_chain.accessible_by(current_ability)
end
end
end
Borrowed from another user's code, but now I can't find the source any more.