1051 lines
32 KiB
Ruby
1051 lines
32 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "abstract_unit"
|
|
|
|
class ActionController::Base
|
|
class << self
|
|
%w(append_around_action prepend_after_action prepend_around_action prepend_before_action skip_after_action skip_before_action).each do |pending|
|
|
define_method(pending) do |*args|
|
|
$stderr.puts "#{pending} unimplemented: #{args.inspect}"
|
|
end unless method_defined?(pending)
|
|
end
|
|
|
|
def before_actions
|
|
filters = _process_action_callbacks.select { |c| c.kind == :before }
|
|
filters.map!(&:raw_filter)
|
|
end
|
|
end
|
|
end
|
|
|
|
class FilterTest < ActionController::TestCase
|
|
class TestController < ActionController::Base
|
|
before_action :ensure_login
|
|
after_action :clean_up
|
|
|
|
def show
|
|
render inline: "ran action"
|
|
end
|
|
|
|
private
|
|
def ensure_login
|
|
@ran_filter ||= []
|
|
@ran_filter << "ensure_login"
|
|
end
|
|
|
|
def clean_up
|
|
@ran_after_action ||= []
|
|
@ran_after_action << "clean_up"
|
|
end
|
|
end
|
|
|
|
class ChangingTheRequirementsController < TestController
|
|
before_action :ensure_login, except: [:go_wild]
|
|
|
|
def go_wild
|
|
render plain: "gobble"
|
|
end
|
|
end
|
|
|
|
class TestMultipleFiltersController < ActionController::Base
|
|
before_action :try_1
|
|
before_action :try_2
|
|
before_action :try_3
|
|
|
|
(1..3).each do |i|
|
|
define_method "fail_#{i}" do
|
|
render plain: i.to_s
|
|
end
|
|
end
|
|
|
|
private
|
|
(1..3).each do |i|
|
|
define_method "try_#{i}" do
|
|
instance_variable_set :@try, i
|
|
if action_name == "fail_#{i}"
|
|
head(404)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
class RenderingController < ActionController::Base
|
|
before_action :before_action_rendering
|
|
after_action :unreached_after_action
|
|
|
|
def show
|
|
@ran_action = true
|
|
render inline: "ran action"
|
|
end
|
|
|
|
private
|
|
def before_action_rendering
|
|
@ran_filter ||= []
|
|
@ran_filter << "before_action_rendering"
|
|
render inline: "something else"
|
|
end
|
|
|
|
def unreached_after_action
|
|
@ran_filter << "unreached_after_action_after_render"
|
|
end
|
|
end
|
|
|
|
class RenderingForPrependAfterActionController < RenderingController
|
|
prepend_after_action :unreached_prepend_after_action
|
|
|
|
private
|
|
def unreached_prepend_after_action
|
|
@ran_filter << "unreached_preprend_after_action_after_render"
|
|
end
|
|
end
|
|
|
|
class BeforeActionRedirectionController < ActionController::Base
|
|
before_action :before_action_redirects
|
|
after_action :unreached_after_action
|
|
|
|
def show
|
|
@ran_action = true
|
|
render inline: "ran show action"
|
|
end
|
|
|
|
def target_of_redirection
|
|
@ran_target_of_redirection = true
|
|
render inline: "ran target_of_redirection action"
|
|
end
|
|
|
|
private
|
|
def before_action_redirects
|
|
@ran_filter ||= []
|
|
@ran_filter << "before_action_redirects"
|
|
redirect_to(action: "target_of_redirection")
|
|
end
|
|
|
|
def unreached_after_action
|
|
@ran_filter << "unreached_after_action_after_redirection"
|
|
end
|
|
end
|
|
|
|
class BeforeActionRedirectionForPrependAfterActionController < BeforeActionRedirectionController
|
|
prepend_after_action :unreached_prepend_after_action_after_redirection
|
|
|
|
private
|
|
def unreached_prepend_after_action_after_redirection
|
|
@ran_filter << "unreached_prepend_after_action_after_redirection"
|
|
end
|
|
end
|
|
|
|
class ConditionalFilterController < ActionController::Base
|
|
def show
|
|
render inline: "ran action"
|
|
end
|
|
|
|
def another_action
|
|
render inline: "ran action"
|
|
end
|
|
|
|
def show_without_action
|
|
render inline: "ran action without action"
|
|
end
|
|
|
|
private
|
|
def ensure_login
|
|
@ran_filter ||= []
|
|
@ran_filter << "ensure_login"
|
|
end
|
|
|
|
def clean_up_tmp
|
|
@ran_filter ||= []
|
|
@ran_filter << "clean_up_tmp"
|
|
end
|
|
end
|
|
|
|
class ConditionalCollectionFilterController < ConditionalFilterController
|
|
before_action :ensure_login, except: [ :show_without_action, :another_action ]
|
|
end
|
|
|
|
class OnlyConditionSymController < ConditionalFilterController
|
|
before_action :ensure_login, only: :show
|
|
end
|
|
|
|
class ExceptConditionSymController < ConditionalFilterController
|
|
before_action :ensure_login, except: :show_without_action
|
|
end
|
|
|
|
class BeforeAndAfterConditionController < ConditionalFilterController
|
|
before_action :ensure_login, only: :show
|
|
after_action :clean_up_tmp, only: :show
|
|
end
|
|
|
|
class OnlyConditionProcController < ConditionalFilterController
|
|
before_action(only: :show) { |c| c.instance_variable_set(:"@ran_proc_action", true) }
|
|
end
|
|
|
|
class ExceptConditionProcController < ConditionalFilterController
|
|
before_action(except: :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action", true) }
|
|
end
|
|
|
|
class ConditionalClassFilter
|
|
def self.before(controller) controller.instance_variable_set(:"@ran_class_action", true) end
|
|
end
|
|
|
|
class OnlyConditionClassController < ConditionalFilterController
|
|
before_action ConditionalClassFilter, only: :show
|
|
end
|
|
|
|
class ExceptConditionClassController < ConditionalFilterController
|
|
before_action ConditionalClassFilter, except: :show_without_action
|
|
end
|
|
|
|
class AnomolousYetValidConditionController < ConditionalFilterController
|
|
before_action(ConditionalClassFilter, :ensure_login, Proc.new { |c| c.instance_variable_set(:"@ran_proc_action1", true) }, except: :show_without_action) { |c| c.instance_variable_set(:"@ran_proc_action2", true) }
|
|
end
|
|
|
|
class OnlyConditionalOptionsFilter < ConditionalFilterController
|
|
before_action :ensure_login, only: :index, if: Proc.new { |c| c.instance_variable_set(:"@ran_conditional_index_proc", true) }
|
|
end
|
|
|
|
class ConditionalOptionsFilter < ConditionalFilterController
|
|
before_action :ensure_login, if: Proc.new { |c| true }
|
|
before_action :clean_up_tmp, if: Proc.new { |c| false }
|
|
end
|
|
|
|
class ConditionalOptionsSkipFilter < ConditionalFilterController
|
|
before_action :ensure_login
|
|
before_action :clean_up_tmp
|
|
|
|
skip_before_action :ensure_login, if: -> { false }
|
|
skip_before_action :clean_up_tmp, if: -> { true }
|
|
end
|
|
|
|
class SkipFilterUsingOnlyAndIf < ConditionalFilterController
|
|
before_action :clean_up_tmp
|
|
before_action :ensure_login
|
|
|
|
skip_before_action :ensure_login, only: :login, if: -> { false }
|
|
skip_before_action :clean_up_tmp, only: :login, if: -> { true }
|
|
|
|
def login
|
|
render plain: "ok"
|
|
end
|
|
end
|
|
|
|
class SkipFilterUsingIfAndExcept < ConditionalFilterController
|
|
before_action :clean_up_tmp
|
|
before_action :ensure_login
|
|
|
|
skip_before_action :ensure_login, if: -> { false }, except: :login
|
|
skip_before_action :clean_up_tmp, if: -> { true }, except: :login
|
|
|
|
def login
|
|
render plain: "ok"
|
|
end
|
|
end
|
|
|
|
class ClassController < ConditionalFilterController
|
|
before_action ConditionalClassFilter
|
|
end
|
|
|
|
class PrependingController < TestController
|
|
prepend_before_action :wonderful_life
|
|
# skip_before_action :fire_flash
|
|
|
|
private
|
|
def wonderful_life
|
|
@ran_filter ||= []
|
|
@ran_filter << "wonderful_life"
|
|
end
|
|
end
|
|
|
|
class SkippingAndLimitedController < TestController
|
|
skip_before_action :ensure_login
|
|
before_action :ensure_login, only: :index
|
|
|
|
def index
|
|
render plain: "ok"
|
|
end
|
|
|
|
def public
|
|
render plain: "ok"
|
|
end
|
|
end
|
|
|
|
class SkippingAndReorderingController < TestController
|
|
skip_before_action :ensure_login
|
|
before_action :find_record
|
|
before_action :ensure_login
|
|
|
|
def index
|
|
render plain: "ok"
|
|
end
|
|
|
|
private
|
|
def find_record
|
|
@ran_filter ||= []
|
|
@ran_filter << "find_record"
|
|
end
|
|
end
|
|
|
|
class ConditionalSkippingController < TestController
|
|
skip_before_action :ensure_login, only: [ :login ]
|
|
skip_after_action :clean_up, only: [ :login ]
|
|
|
|
before_action :find_user, only: [ :change_password ]
|
|
|
|
def login
|
|
render inline: "ran action"
|
|
end
|
|
|
|
def change_password
|
|
render inline: "ran action"
|
|
end
|
|
|
|
private
|
|
def find_user
|
|
@ran_filter ||= []
|
|
@ran_filter << "find_user"
|
|
end
|
|
end
|
|
|
|
class ConditionalParentOfConditionalSkippingController < ConditionalFilterController
|
|
before_action :conditional_in_parent_before, only: [:show, :another_action]
|
|
after_action :conditional_in_parent_after, only: [:show, :another_action]
|
|
|
|
private
|
|
|
|
def conditional_in_parent_before
|
|
@ran_filter ||= []
|
|
@ran_filter << "conditional_in_parent_before"
|
|
end
|
|
|
|
def conditional_in_parent_after
|
|
@ran_filter ||= []
|
|
@ran_filter << "conditional_in_parent_after"
|
|
end
|
|
end
|
|
|
|
class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
|
|
skip_before_action :conditional_in_parent_before, only: :another_action
|
|
skip_after_action :conditional_in_parent_after, only: :another_action
|
|
end
|
|
|
|
class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController
|
|
skip_before_action :conditional_in_parent_before, only: :show
|
|
end
|
|
|
|
class ProcController < PrependingController
|
|
before_action(proc { |c| c.instance_variable_set(:"@ran_proc_action", true) })
|
|
end
|
|
|
|
class ImplicitProcController < PrependingController
|
|
before_action { |c| c.instance_variable_set(:"@ran_proc_action", true) }
|
|
end
|
|
|
|
class AuditFilter
|
|
def self.before(controller)
|
|
controller.instance_variable_set(:"@was_audited", true)
|
|
end
|
|
end
|
|
|
|
class AroundFilter
|
|
def before(controller)
|
|
@execution_log = "before"
|
|
controller.class.execution_log += " before aroundfilter " if controller.respond_to? :execution_log
|
|
controller.instance_variable_set(:"@before_ran", true)
|
|
end
|
|
|
|
def after(controller)
|
|
controller.instance_variable_set(:"@execution_log", @execution_log + " and after")
|
|
controller.instance_variable_set(:"@after_ran", true)
|
|
controller.class.execution_log << " after aroundfilter " if controller.respond_to? :execution_log
|
|
end
|
|
|
|
def around(controller)
|
|
before(controller)
|
|
yield
|
|
after(controller)
|
|
end
|
|
end
|
|
|
|
class AppendedAroundFilter
|
|
def before(controller)
|
|
controller.class.execution_log << " before appended aroundfilter "
|
|
end
|
|
|
|
def after(controller)
|
|
controller.class.execution_log << " after appended aroundfilter "
|
|
end
|
|
|
|
def around(controller)
|
|
before(controller)
|
|
yield
|
|
after(controller)
|
|
end
|
|
end
|
|
|
|
class AuditController < ActionController::Base
|
|
before_action(AuditFilter)
|
|
|
|
def show
|
|
render plain: "hello"
|
|
end
|
|
end
|
|
|
|
class AroundFilterController < PrependingController
|
|
around_action AroundFilter.new
|
|
end
|
|
|
|
class BeforeAfterClassFilterController < PrependingController
|
|
begin
|
|
filter = AroundFilter.new
|
|
before_action filter
|
|
after_action filter
|
|
end
|
|
end
|
|
|
|
class MixedFilterController < PrependingController
|
|
cattr_accessor :execution_log
|
|
|
|
def initialize
|
|
@@execution_log = ""
|
|
super()
|
|
end
|
|
|
|
before_action { |c| c.class.execution_log << " before procfilter " }
|
|
prepend_around_action AroundFilter.new
|
|
|
|
after_action { |c| c.class.execution_log << " after procfilter " }
|
|
append_around_action AppendedAroundFilter.new
|
|
end
|
|
|
|
class MixedSpecializationController < ActionController::Base
|
|
class OutOfOrder < StandardError; end
|
|
|
|
before_action :first
|
|
before_action :second, only: :foo
|
|
|
|
def foo
|
|
render plain: "foo"
|
|
end
|
|
|
|
def bar
|
|
render plain: "bar"
|
|
end
|
|
|
|
private
|
|
def first
|
|
@first = true
|
|
end
|
|
|
|
def second
|
|
raise OutOfOrder unless @first
|
|
end
|
|
end
|
|
|
|
class DynamicDispatchController < ActionController::Base
|
|
before_action :choose
|
|
|
|
%w(foo bar baz).each do |action|
|
|
define_method(action) { render plain: action }
|
|
end
|
|
|
|
private
|
|
def choose
|
|
self.action_name = params[:choose]
|
|
end
|
|
end
|
|
|
|
class PrependingBeforeAndAfterController < ActionController::Base
|
|
prepend_before_action :before_all
|
|
prepend_after_action :after_all
|
|
before_action :between_before_all_and_after_all
|
|
|
|
def before_all
|
|
@ran_filter ||= []
|
|
@ran_filter << "before_all"
|
|
end
|
|
|
|
def after_all
|
|
@ran_filter ||= []
|
|
@ran_filter << "after_all"
|
|
end
|
|
|
|
def between_before_all_and_after_all
|
|
@ran_filter ||= []
|
|
@ran_filter << "between_before_all_and_after_all"
|
|
end
|
|
def show
|
|
render plain: "hello"
|
|
end
|
|
end
|
|
|
|
class ErrorToRescue < Exception; end
|
|
|
|
class RescuingAroundFilterWithBlock
|
|
def around(controller)
|
|
yield
|
|
rescue ErrorToRescue => ex
|
|
controller.__send__ :render, plain: "I rescued this: #{ex.inspect}"
|
|
end
|
|
end
|
|
|
|
class RescuedController < ActionController::Base
|
|
around_action RescuingAroundFilterWithBlock.new
|
|
|
|
def show
|
|
raise ErrorToRescue.new("Something made the bad noise.")
|
|
end
|
|
end
|
|
|
|
class NonYieldingAroundFilterController < ActionController::Base
|
|
before_action :filter_one
|
|
around_action :non_yielding_action
|
|
before_action :action_two
|
|
after_action :action_three
|
|
|
|
def index
|
|
render inline: "index"
|
|
end
|
|
|
|
private
|
|
|
|
def filter_one
|
|
@filters ||= []
|
|
@filters << "filter_one"
|
|
end
|
|
|
|
def action_two
|
|
@filters << "action_two"
|
|
end
|
|
|
|
def non_yielding_action
|
|
@filters << "it didn't yield"
|
|
end
|
|
|
|
def action_three
|
|
@filters << "action_three"
|
|
end
|
|
end
|
|
|
|
class ImplicitActionsController < ActionController::Base
|
|
before_action :find_only, only: :edit
|
|
before_action :find_except, except: :edit
|
|
|
|
private
|
|
|
|
def find_only
|
|
@only = "Only"
|
|
end
|
|
|
|
def find_except
|
|
@except = "Except"
|
|
end
|
|
end
|
|
|
|
def test_non_yielding_around_actions_do_not_raise
|
|
controller = NonYieldingAroundFilterController.new
|
|
assert_nothing_raised do
|
|
test_process(controller, "index")
|
|
end
|
|
end
|
|
|
|
def test_after_actions_are_not_run_if_around_action_does_not_yield
|
|
controller = NonYieldingAroundFilterController.new
|
|
test_process(controller, "index")
|
|
assert_equal ["filter_one", "it didn't yield"], controller.instance_variable_get(:@filters)
|
|
end
|
|
|
|
def test_added_action_to_inheritance_graph
|
|
assert_equal [ :ensure_login ], TestController.before_actions
|
|
end
|
|
|
|
def test_base_class_in_isolation
|
|
assert_equal [ ], ActionController::Base.before_actions
|
|
end
|
|
|
|
def test_prepending_action
|
|
assert_equal [ :wonderful_life, :ensure_login ], PrependingController.before_actions
|
|
end
|
|
|
|
def test_running_actions
|
|
test_process(PrependingController)
|
|
assert_equal %w( wonderful_life ensure_login ),
|
|
@controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_running_actions_with_proc
|
|
test_process(ProcController)
|
|
assert @controller.instance_variable_get(:@ran_proc_action)
|
|
end
|
|
|
|
def test_running_actions_with_implicit_proc
|
|
test_process(ImplicitProcController)
|
|
assert @controller.instance_variable_get(:@ran_proc_action)
|
|
end
|
|
|
|
def test_running_actions_with_class
|
|
test_process(AuditController)
|
|
assert @controller.instance_variable_get(:@was_audited)
|
|
end
|
|
|
|
def test_running_anomalous_yet_valid_condition_actions
|
|
test_process(AnomolousYetValidConditionController)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
assert @controller.instance_variable_get(:@ran_class_action)
|
|
assert @controller.instance_variable_get(:@ran_proc_action1)
|
|
assert @controller.instance_variable_get(:@ran_proc_action2)
|
|
|
|
test_process(AnomolousYetValidConditionController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
assert_not @controller.instance_variable_defined?(:@ran_class_action)
|
|
assert_not @controller.instance_variable_defined?(:@ran_proc_action1)
|
|
assert_not @controller.instance_variable_defined?(:@ran_proc_action2)
|
|
end
|
|
|
|
def test_running_conditional_options
|
|
test_process(ConditionalOptionsFilter)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_running_conditional_skip_options
|
|
test_process(ConditionalOptionsSkipFilter)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_if_is_ignored_when_used_with_only
|
|
test_process(SkipFilterUsingOnlyAndIf, "login")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_except_is_ignored_when_used_with_if
|
|
test_process(SkipFilterUsingIfAndExcept, "login")
|
|
assert_equal %w(ensure_login), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_skipping_class_actions
|
|
test_process(ClassController)
|
|
assert_equal true, @controller.instance_variable_get(:@ran_class_action)
|
|
|
|
skipping_class_controller = Class.new(ClassController) do
|
|
skip_before_action ConditionalClassFilter
|
|
end
|
|
|
|
test_process(skipping_class_controller)
|
|
assert_not @controller.instance_variable_defined?(:@ran_class_action)
|
|
end
|
|
|
|
def test_running_collection_condition_actions
|
|
test_process(ConditionalCollectionFilterController)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(ConditionalCollectionFilterController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
test_process(ConditionalCollectionFilterController, "another_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_running_only_condition_actions
|
|
test_process(OnlyConditionSymController)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(OnlyConditionSymController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
|
|
test_process(OnlyConditionProcController)
|
|
assert @controller.instance_variable_get(:@ran_proc_action)
|
|
test_process(OnlyConditionProcController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_proc_action)
|
|
|
|
test_process(OnlyConditionClassController)
|
|
assert @controller.instance_variable_get(:@ran_class_action)
|
|
test_process(OnlyConditionClassController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_class_action)
|
|
end
|
|
|
|
def test_running_except_condition_actions
|
|
test_process(ExceptConditionSymController)
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(ExceptConditionSymController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
|
|
test_process(ExceptConditionProcController)
|
|
assert @controller.instance_variable_get(:@ran_proc_action)
|
|
test_process(ExceptConditionProcController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_proc_action)
|
|
|
|
test_process(ExceptConditionClassController)
|
|
assert @controller.instance_variable_get(:@ran_class_action)
|
|
test_process(ExceptConditionClassController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_class_action)
|
|
end
|
|
|
|
def test_running_only_condition_and_conditional_options
|
|
test_process(OnlyConditionalOptionsFilter, "show")
|
|
assert_not @controller.instance_variable_defined?(:@ran_conditional_index_proc)
|
|
end
|
|
|
|
def test_running_before_and_after_condition_actions
|
|
test_process(BeforeAndAfterConditionController)
|
|
assert_equal %w( ensure_login clean_up_tmp), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(BeforeAndAfterConditionController, "show_without_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_around_action
|
|
test_process(AroundFilterController)
|
|
assert @controller.instance_variable_get(:@before_ran)
|
|
assert @controller.instance_variable_get(:@after_ran)
|
|
end
|
|
|
|
def test_before_after_class_action
|
|
test_process(BeforeAfterClassFilterController)
|
|
assert @controller.instance_variable_get(:@before_ran)
|
|
assert @controller.instance_variable_get(:@after_ran)
|
|
end
|
|
|
|
def test_having_properties_in_around_action
|
|
test_process(AroundFilterController)
|
|
assert_equal "before and after", @controller.instance_variable_get(:@execution_log)
|
|
end
|
|
|
|
def test_prepending_and_appending_around_action
|
|
test_process(MixedFilterController)
|
|
assert_equal " before aroundfilter before procfilter before appended aroundfilter " \
|
|
" after appended aroundfilter after procfilter after aroundfilter ",
|
|
MixedFilterController.execution_log
|
|
end
|
|
|
|
def test_rendering_breaks_actioning_chain
|
|
response = test_process(RenderingController)
|
|
assert_equal "something else", response.body
|
|
assert_not @controller.instance_variable_defined?(:@ran_action)
|
|
end
|
|
|
|
def test_before_action_rendering_breaks_actioning_chain_for_after_action
|
|
test_process(RenderingController)
|
|
assert_equal %w( before_action_rendering ), @controller.instance_variable_get(:@ran_filter)
|
|
assert_not @controller.instance_variable_defined?(:@ran_action)
|
|
end
|
|
|
|
def test_before_action_redirects_breaks_actioning_chain_for_after_action
|
|
test_process(BeforeActionRedirectionController)
|
|
assert_response :redirect
|
|
assert_equal "http://test.host/filter_test/before_action_redirection/target_of_redirection", redirect_to_url
|
|
assert_equal %w( before_action_redirects ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_before_action_rendering_breaks_actioning_chain_for_preprend_after_action
|
|
test_process(RenderingForPrependAfterActionController)
|
|
assert_equal %w( before_action_rendering ), @controller.instance_variable_get(:@ran_filter)
|
|
assert_not @controller.instance_variable_defined?(:@ran_action)
|
|
end
|
|
|
|
def test_before_action_redirects_breaks_actioning_chain_for_preprend_after_action
|
|
test_process(BeforeActionRedirectionForPrependAfterActionController)
|
|
assert_response :redirect
|
|
assert_equal "http://test.host/filter_test/before_action_redirection_for_prepend_after_action/target_of_redirection", redirect_to_url
|
|
assert_equal %w( before_action_redirects ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_actions_with_mixed_specialization_run_in_order
|
|
assert_nothing_raised do
|
|
response = test_process(MixedSpecializationController, "bar")
|
|
assert_equal "bar", response.body
|
|
end
|
|
|
|
assert_nothing_raised do
|
|
response = test_process(MixedSpecializationController, "foo")
|
|
assert_equal "foo", response.body
|
|
end
|
|
end
|
|
|
|
def test_dynamic_dispatch
|
|
%w(foo bar baz).each do |action|
|
|
@request.query_parameters[:choose] = action
|
|
response = DynamicDispatchController.action(action).call(@request.env).last
|
|
assert_equal action, response.body
|
|
end
|
|
end
|
|
|
|
def test_running_prepended_before_and_after_action
|
|
test_process(PrependingBeforeAndAfterController)
|
|
assert_equal %w( before_all between_before_all_and_after_all after_all ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_skipping_and_limiting_controller
|
|
test_process(SkippingAndLimitedController, "index")
|
|
assert_equal %w( ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(SkippingAndLimitedController, "public")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_skipping_and_reordering_controller
|
|
test_process(SkippingAndReorderingController, "index")
|
|
assert_equal %w( find_record ensure_login ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_conditional_skipping_of_actions
|
|
test_process(ConditionalSkippingController, "login")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
test_process(ConditionalSkippingController, "change_password")
|
|
assert_equal %w( ensure_login find_user ), @controller.instance_variable_get(:@ran_filter)
|
|
|
|
test_process(ConditionalSkippingController, "login")
|
|
assert !@controller.instance_variable_defined?("@ran_after_action")
|
|
test_process(ConditionalSkippingController, "change_password")
|
|
assert_equal %w( clean_up ), @controller.instance_variable_get("@ran_after_action")
|
|
end
|
|
|
|
def test_conditional_skipping_of_actions_when_parent_action_is_also_conditional
|
|
test_process(ChildOfConditionalParentController)
|
|
assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(ChildOfConditionalParentController, "another_action")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_condition_skipping_of_actions_when_siblings_also_have_conditions
|
|
test_process(ChildOfConditionalParentController)
|
|
assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(AnotherChildOfConditionalParentController)
|
|
assert_equal %w( conditional_in_parent_after ), @controller.instance_variable_get(:@ran_filter)
|
|
test_process(ChildOfConditionalParentController)
|
|
assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), @controller.instance_variable_get(:@ran_filter)
|
|
end
|
|
|
|
def test_changing_the_requirements
|
|
test_process(ChangingTheRequirementsController, "go_wild")
|
|
assert_not @controller.instance_variable_defined?(:@ran_filter)
|
|
end
|
|
|
|
def test_a_rescuing_around_action
|
|
response = nil
|
|
assert_nothing_raised do
|
|
response = test_process(RescuedController)
|
|
end
|
|
|
|
assert response.successful?
|
|
assert_equal("I rescued this: #<FilterTest::ErrorToRescue: Something made the bad noise.>", response.body)
|
|
end
|
|
|
|
def test_actions_obey_only_and_except_for_implicit_actions
|
|
test_process(ImplicitActionsController, "show")
|
|
assert_equal "Except", @controller.instance_variable_get(:@except)
|
|
assert_not @controller.instance_variable_defined?(:@only)
|
|
assert_equal "show", response.body
|
|
|
|
test_process(ImplicitActionsController, "edit")
|
|
assert_equal "Only", @controller.instance_variable_get(:@only)
|
|
assert_not @controller.instance_variable_defined?(:@except)
|
|
assert_equal "edit", response.body
|
|
end
|
|
|
|
private
|
|
def test_process(controller, action = "show")
|
|
@controller = controller.is_a?(Class) ? controller.new : controller
|
|
|
|
process(action)
|
|
end
|
|
end
|
|
|
|
class PostsController < ActionController::Base
|
|
module AroundExceptions
|
|
class Error < StandardError ; end
|
|
class Before < Error ; end
|
|
class After < Error ; end
|
|
end
|
|
include AroundExceptions
|
|
|
|
class DefaultFilter
|
|
include AroundExceptions
|
|
end
|
|
|
|
module_eval %w(raises_before raises_after raises_both no_raise no_action).map { |action| "def #{action}; default_action end" }.join("\n")
|
|
|
|
private
|
|
def default_action
|
|
render inline: "#{action_name} called"
|
|
end
|
|
end
|
|
|
|
class ControllerWithSymbolAsFilter < PostsController
|
|
around_action :raise_before, only: :raises_before
|
|
around_action :raise_after, only: :raises_after
|
|
around_action :without_exception, only: :no_raise
|
|
|
|
private
|
|
def raise_before
|
|
raise Before
|
|
yield
|
|
end
|
|
|
|
def raise_after
|
|
yield
|
|
raise After
|
|
end
|
|
|
|
def without_exception
|
|
# Do stuff...
|
|
wtf = 1 + 1
|
|
|
|
yield
|
|
|
|
# Do stuff...
|
|
wtf += 1
|
|
end
|
|
end
|
|
|
|
class ControllerWithFilterClass < PostsController
|
|
class YieldingFilter < DefaultFilter
|
|
def self.around(controller)
|
|
yield
|
|
raise After
|
|
end
|
|
end
|
|
|
|
around_action YieldingFilter, only: :raises_after
|
|
end
|
|
|
|
class ControllerWithFilterInstance < PostsController
|
|
class YieldingFilter < DefaultFilter
|
|
def around(controller)
|
|
yield
|
|
raise After
|
|
end
|
|
end
|
|
|
|
around_action YieldingFilter.new, only: :raises_after
|
|
end
|
|
|
|
class ControllerWithProcFilter < PostsController
|
|
around_action(only: :no_raise) do |c, b|
|
|
c.instance_variable_set(:"@before", true)
|
|
b.call
|
|
c.instance_variable_set(:"@after", true)
|
|
end
|
|
end
|
|
|
|
class ControllerWithNestedFilters < ControllerWithSymbolAsFilter
|
|
around_action :raise_before, :raise_after, :without_exception, only: :raises_both
|
|
end
|
|
|
|
class ControllerWithAllTypesOfFilters < PostsController
|
|
before_action :before
|
|
around_action :around
|
|
after_action :after
|
|
around_action :around_again
|
|
|
|
private
|
|
def before
|
|
@ran_filter ||= []
|
|
@ran_filter << "before"
|
|
end
|
|
|
|
def around
|
|
@ran_filter << "around (before yield)"
|
|
yield
|
|
@ran_filter << "around (after yield)"
|
|
end
|
|
|
|
def after
|
|
@ran_filter << "after"
|
|
end
|
|
|
|
def around_again
|
|
@ran_filter << "around_again (before yield)"
|
|
yield
|
|
@ran_filter << "around_again (after yield)"
|
|
end
|
|
end
|
|
|
|
class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters
|
|
skip_around_action :around_again
|
|
skip_after_action :after
|
|
end
|
|
|
|
class YieldingAroundFiltersTest < ActionController::TestCase
|
|
include PostsController::AroundExceptions
|
|
|
|
def test_base
|
|
controller = PostsController
|
|
assert_nothing_raised { test_process(controller, "no_raise") }
|
|
assert_nothing_raised { test_process(controller, "raises_before") }
|
|
assert_nothing_raised { test_process(controller, "raises_after") }
|
|
assert_nothing_raised { test_process(controller, "no_action") }
|
|
end
|
|
|
|
def test_with_symbol
|
|
controller = ControllerWithSymbolAsFilter
|
|
assert_nothing_raised { test_process(controller, "no_raise") }
|
|
assert_raise(Before) { test_process(controller, "raises_before") }
|
|
assert_raise(After) { test_process(controller, "raises_after") }
|
|
assert_nothing_raised { test_process(controller, "no_raise") }
|
|
end
|
|
|
|
def test_with_class
|
|
controller = ControllerWithFilterClass
|
|
assert_nothing_raised { test_process(controller, "no_raise") }
|
|
assert_raise(After) { test_process(controller, "raises_after") }
|
|
end
|
|
|
|
def test_with_instance
|
|
controller = ControllerWithFilterInstance
|
|
assert_nothing_raised { test_process(controller, "no_raise") }
|
|
assert_raise(After) { test_process(controller, "raises_after") }
|
|
end
|
|
|
|
def test_with_proc
|
|
test_process(ControllerWithProcFilter, "no_raise")
|
|
assert @controller.instance_variable_get(:@before)
|
|
assert @controller.instance_variable_get(:@after)
|
|
end
|
|
|
|
def test_nested_actions
|
|
controller = ControllerWithNestedFilters
|
|
assert_nothing_raised do
|
|
begin
|
|
test_process(controller, "raises_both")
|
|
rescue Before, After
|
|
end
|
|
end
|
|
assert_raise Before do
|
|
begin
|
|
test_process(controller, "raises_both")
|
|
rescue After
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_action_order_with_all_action_types
|
|
test_process(ControllerWithAllTypesOfFilters, "no_raise")
|
|
assert_equal "before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)", @controller.instance_variable_get(:@ran_filter).join(" ")
|
|
end
|
|
|
|
def test_action_order_with_skip_action_method
|
|
test_process(ControllerWithTwoLessFilters, "no_raise")
|
|
assert_equal "before around (before yield) around (after yield)", @controller.instance_variable_get(:@ran_filter).join(" ")
|
|
end
|
|
|
|
def test_first_action_in_multiple_before_action_chain_halts
|
|
controller = ::FilterTest::TestMultipleFiltersController.new
|
|
response = test_process(controller, "fail_1")
|
|
assert_equal "", response.body
|
|
assert_equal 1, controller.instance_variable_get(:@try)
|
|
end
|
|
|
|
def test_second_action_in_multiple_before_action_chain_halts
|
|
controller = ::FilterTest::TestMultipleFiltersController.new
|
|
response = test_process(controller, "fail_2")
|
|
assert_equal "", response.body
|
|
assert_equal 2, controller.instance_variable_get(:@try)
|
|
end
|
|
|
|
def test_last_action_in_multiple_before_action_chain_halts
|
|
controller = ::FilterTest::TestMultipleFiltersController.new
|
|
response = test_process(controller, "fail_3")
|
|
assert_equal "", response.body
|
|
assert_equal 3, controller.instance_variable_get(:@try)
|
|
end
|
|
|
|
private
|
|
def test_process(controller, action = "show")
|
|
@controller = controller.is_a?(Class) ? controller.new : controller
|
|
process(action)
|
|
end
|
|
end
|