conditionally apply skip_before_filter with :if =>

2019-04-26 09:20发布

问题:

I have an Events Controller on which I want to skip authentication incase the event is public.

In my ApplicationController I have this call to devise's authenticate_user!

class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end

now, Inside my Events table, I have a boolean field called public. I use that to check if event is public or not. Like this in EventsController

class EventsController < ApplicationController
  skip_before_action :authenticate_user!, only: :show, if: Proc.new { :is_public? }
end

But for some reason, this didn't work. so I had to do this:

class EventsController < ApplicationController
  skip_before_action :authenticate_user!, only: :show
  before_action :authenticate_user!, unless: :is_public?

  def is_public?
    @event.present? && @event.is_public
  end
end

This works as expects and skip authentication if @event.public = true because the above repeats the before_filter with the inverse condition after skipping.

I am wondering:

  1. what I did is correct?
  2. Does this have any performance impact. if yes, then Is there a better way?

回答1:

the rails documentation on callbacks (before, after, around action) is actually pretty bad. see this similar question: skip_before_filter ignores conditionals

so i always refer to the rails guides. the part that would be interesting for you is here: http://guides.rubyonrails.org/action_controller_overview.html#other-ways-to-use-filters

i am not totally sure that this would work with skip filter as well, but it is worth a try.

there should not be a performance impact just by calling different filters. the performance issues usually come by extensive database queries or other external system calls.

my main concern here would be that it is pretty hard to understand why there are so many before_action things going on...