| | 247 | |
|---|
| | 248 | class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc: |
|---|
| | 249 | def append_filter_to_chain(filters, filter_type, &block) |
|---|
| | 250 | pos = find_filter_append_position(filters, filter_type) |
|---|
| | 251 | update_filter_chain(filters, filter_type, pos, &block) |
|---|
| | 252 | end |
|---|
| | 253 | |
|---|
| | 254 | def prepend_filter_to_chain(filters, filter_type, &block) |
|---|
| | 255 | pos = find_filter_prepend_position(filters, filter_type) |
|---|
| | 256 | update_filter_chain(filters, filter_type, pos, &block) |
|---|
| | 257 | end |
|---|
| | 258 | |
|---|
| | 259 | def create_filters(filters, filter_type, &block) |
|---|
| | 260 | filters, conditions = extract_options(filters, &block) |
|---|
| | 261 | filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) } |
|---|
| | 262 | filters |
|---|
| | 263 | end |
|---|
| | 264 | |
|---|
| | 265 | def skip_filter_in_chain(*filters, &test) |
|---|
| | 266 | filters, conditions = extract_options(filters) |
|---|
| | 267 | update_filter_in_chain(filters, :skip => conditions, &test) |
|---|
| | 268 | end |
|---|
| | 269 | |
|---|
| | 270 | private |
|---|
| | 271 | def update_filter_chain(filters, filter_type, pos, &block) |
|---|
| | 272 | new_filters = create_filters(filters, filter_type, &block) |
|---|
| | 273 | insert(pos, new_filters).flatten! |
|---|
| | 274 | end |
|---|
| | 275 | |
|---|
| | 276 | def find_filter_append_position(filters, filter_type) |
|---|
| | 277 | # appending an after filter puts it at the end of the call chain |
|---|
| | 278 | # before and around filters go before the first after filter in the chain |
|---|
| | 279 | unless filter_type == :after |
|---|
| | 280 | each_with_index do |f,i| |
|---|
| | 281 | return i if f.after? |
|---|
| | 282 | end |
|---|
| | 283 | end |
|---|
| | 284 | return -1 |
|---|
| | 285 | end |
|---|
| | 286 | |
|---|
| | 287 | def find_filter_prepend_position(filters, filter_type) |
|---|
| | 288 | # prepending a before or around filter puts it at the front of the call chain |
|---|
| | 289 | # after filters go before the first after filter in the chain |
|---|
| | 290 | if filter_type == :after |
|---|
| | 291 | each_with_index do |f,i| |
|---|
| | 292 | return i if f.after? |
|---|
| | 293 | end |
|---|
| | 294 | return -1 |
|---|
| | 295 | end |
|---|
| | 296 | return 0 |
|---|
| | 297 | end |
|---|
| | 298 | |
|---|
| | 299 | def find_or_create_filter(filter, filter_type, options = {}) |
|---|
| | 300 | update_filter_in_chain([filter], options) |
|---|
| | 301 | |
|---|
| | 302 | if found_filter = find_callback(filter) { |f| f.type == filter_type } |
|---|
| | 303 | found_filter |
|---|
| | 304 | else |
|---|
| | 305 | filter_kind = case |
|---|
| | 306 | when filter.respond_to?(:before) && filter_type == :before |
|---|
| | 307 | :before |
|---|
| | 308 | when filter.respond_to?(:after) && filter_type == :after |
|---|
| | 309 | :after |
|---|
| | 310 | else |
|---|
| | 311 | :filter |
|---|
| | 312 | end |
|---|
| | 313 | |
|---|
| | 314 | case filter_type |
|---|
| | 315 | when :before |
|---|
| | 316 | BeforeFilter.new(filter_kind, filter, options) |
|---|
| | 317 | when :after |
|---|
| | 318 | AfterFilter.new(filter_kind, filter, options) |
|---|
| | 319 | else |
|---|
| | 320 | AroundFilter.new(filter_kind, filter, options) |
|---|
| | 321 | end |
|---|
| | 322 | end |
|---|
| | 323 | end |
|---|
| | 324 | |
|---|
| | 325 | def update_filter_in_chain(filters, options, &test) |
|---|
| | 326 | filters.map! { |f| block_given? ? find_callback(f, &test) : find_callback(f) } |
|---|
| | 327 | filters.compact! |
|---|
| | 328 | |
|---|
| | 329 | map! do |filter| |
|---|
| | 330 | if filters.include?(filter) |
|---|
| | 331 | new_filter = filter.dup |
|---|
| | 332 | new_filter.options.merge!(options) |
|---|
| | 333 | new_filter |
|---|
| | 334 | else |
|---|
| | 335 | filter |
|---|
| | 336 | end |
|---|
| | 337 | end |
|---|
| | 338 | end |
|---|
| | 339 | end |
|---|
| | 340 | |
|---|
| | 341 | class Filter < ActiveSupport::Callbacks::Callback #:nodoc: |
|---|
| | 342 | def before? |
|---|
| | 343 | self.class == BeforeFilter |
|---|
| | 344 | end |
|---|
| | 345 | |
|---|
| | 346 | def after? |
|---|
| | 347 | self.class == AfterFilter |
|---|
| | 348 | end |
|---|
| | 349 | |
|---|
| | 350 | def around? |
|---|
| | 351 | self.class == AroundFilter |
|---|
| | 352 | end |
|---|
| | 353 | |
|---|
| | 354 | private |
|---|
| | 355 | def should_not_skip?(controller) |
|---|
| | 356 | if options[:skip] |
|---|
| | 357 | !included_in_action?(controller, options[:skip]) |
|---|
| | 358 | else |
|---|
| | 359 | true |
|---|
| | 360 | end |
|---|
| | 361 | end |
|---|
| | 362 | |
|---|
| | 363 | def included_in_action?(controller, options) |
|---|
| | 364 | if options[:only] |
|---|
| | 365 | Array(options[:only]).map(&:to_s).include?(controller.action_name) |
|---|
| | 366 | elsif options[:except] |
|---|
| | 367 | !Array(options[:except]).map(&:to_s).include?(controller.action_name) |
|---|
| | 368 | else |
|---|
| | 369 | true |
|---|
| | 370 | end |
|---|
| | 371 | end |
|---|
| | 372 | |
|---|
| | 373 | def should_run_callback?(controller) |
|---|
| | 374 | should_not_skip?(controller) && included_in_action?(controller, options) && super |
|---|
| | 375 | end |
|---|
| | 376 | end |
|---|
| | 377 | |
|---|
| | 378 | class AroundFilter < Filter #:nodoc: |
|---|
| | 379 | def type |
|---|
| | 380 | :around |
|---|
| | 381 | end |
|---|
| | 382 | |
|---|
| | 383 | def call(controller, &block) |
|---|
| | 384 | if should_run_callback?(controller) |
|---|
| | 385 | proc = filter_responds_to_before_and_after? ? around_proc : method |
|---|
| | 386 | evaluate_method(proc, controller, &block) |
|---|
| | 387 | else |
|---|
| | 388 | block.call |
|---|
| | 389 | end |
|---|
| | 390 | end |
|---|
| | 391 | |
|---|
| | 392 | private |
|---|
| | 393 | def filter_responds_to_before_and_after? |
|---|
| | 394 | method.respond_to?(:before) && method.respond_to?(:after) |
|---|
| | 395 | end |
|---|
| | 396 | |
|---|
| | 397 | def around_proc |
|---|
| | 398 | Proc.new do |controller, action| |
|---|
| | 399 | method.before(controller) |
|---|
| | 400 | |
|---|
| | 401 | if controller.send!(:performed?) |
|---|
| | 402 | controller.send!(:halt_filter_chain, method, :rendered_or_redirected) |
|---|
| | 403 | else |
|---|
| | 404 | begin |
|---|
| | 405 | action.call |
|---|
| | 406 | ensure |
|---|
| | 407 | method.after(controller) |
|---|
| | 408 | end |
|---|
| | 409 | end |
|---|
| | 410 | end |
|---|
| | 411 | end |
|---|
| | 412 | end |
|---|
| | 413 | |
|---|
| | 414 | class BeforeFilter < Filter #:nodoc: |
|---|
| | 415 | def type |
|---|
| | 416 | :before |
|---|
| | 417 | end |
|---|
| | 418 | |
|---|
| | 419 | def call(controller, &block) |
|---|
| | 420 | super |
|---|
| | 421 | if controller.send!(:performed?) |
|---|
| | 422 | controller.send!(:halt_filter_chain, method, :rendered_or_redirected) |
|---|
| | 423 | end |
|---|
| | 424 | end |
|---|
| | 425 | end |
|---|
| | 426 | |
|---|
| | 427 | class AfterFilter < Filter #:nodoc: |
|---|
| | 428 | def type |
|---|
| | 429 | :after |
|---|
| | 430 | end |
|---|
| | 431 | end |
|---|
| | 432 | |
|---|
| 360 | | filter_chain.select(&:after?).map(&:filter) |
|---|
| 361 | | end |
|---|
| 362 | | |
|---|
| 363 | | # Returns a mapping between filters and the actions that may run them. |
|---|
| 364 | | def included_actions #:nodoc: |
|---|
| 365 | | @included_actions ||= read_inheritable_attribute("included_actions") || {} |
|---|
| 366 | | end |
|---|
| 367 | | |
|---|
| 368 | | # Returns a mapping between filters and actions that may not run them. |
|---|
| 369 | | def excluded_actions #:nodoc: |
|---|
| 370 | | @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {} |
|---|
| 371 | | end |
|---|
| 372 | | |
|---|
| 373 | | # Find a filter in the filter_chain where the filter method matches the _filter_ param |
|---|
| 374 | | # and (optionally) the passed block evaluates to true (mostly used for testing before? |
|---|
| 375 | | # and after? on the filter). Useful for symbol filters. |
|---|
| 376 | | # |
|---|
| 377 | | # The object of type Filter is passed to the block when yielded, not the filter itself. |
|---|
| 378 | | def find_filter(filter, &block) #:nodoc: |
|---|
| 379 | | filter_chain.select { |f| f.filter == filter && (!block_given? || yield(f)) }.first |
|---|
| 380 | | end |
|---|
| 381 | | |
|---|
| 382 | | # Returns true if the filter is excluded from the given action |
|---|
| 383 | | def filter_excluded_from_action?(filter,action) #:nodoc: |
|---|
| 384 | | case |
|---|
| 385 | | when ia = included_actions[filter] |
|---|
| 386 | | !ia.include?(action) |
|---|
| 387 | | when ea = excluded_actions[filter] |
|---|
| 388 | | ea.include?(action) |
|---|
| 389 | | end |
|---|
| 390 | | end |
|---|
| 391 | | |
|---|
| 392 | | # Filter class is an abstract base class for all filters. Handles all of the included/excluded actions but |
|---|
| 393 | | # contains no logic for calling the actual filters. |
|---|
| 394 | | class Filter #:nodoc: |
|---|
| 395 | | attr_reader :filter, :included_actions, :excluded_actions |
|---|
| 396 | | |
|---|
| 397 | | def initialize(filter) |
|---|
| 398 | | @filter = filter |
|---|
| 399 | | end |
|---|
| 400 | | |
|---|
| 401 | | def type |
|---|
| 402 | | :around |
|---|
| 403 | | end |
|---|
| 404 | | |
|---|
| 405 | | def before? |
|---|
| 406 | | type == :before |
|---|
| 407 | | end |
|---|
| 408 | | |
|---|
| 409 | | def after? |
|---|
| 410 | | type == :after |
|---|
| 411 | | end |
|---|
| 412 | | |
|---|
| 413 | | def around? |
|---|
| 414 | | type == :around |
|---|
| 415 | | end |
|---|
| 416 | | |
|---|
| 417 | | def run(controller) |
|---|
| 418 | | raise ActionControllerError, 'No filter type: Nothing to do here.' |
|---|
| 419 | | end |
|---|
| 420 | | |
|---|
| 421 | | def call(controller, &block) |
|---|
| 422 | | run(controller) |
|---|
| 423 | | end |
|---|
| 424 | | end |
|---|
| 425 | | |
|---|
| 426 | | # Abstract base class for filter proxies. FilterProxy objects are meant to mimic the behaviour of the old |
|---|
| 427 | | # before_filter and after_filter by moving the logic into the filter itself. |
|---|
| 428 | | class FilterProxy < Filter #:nodoc: |
|---|
| 429 | | def filter |
|---|
| 430 | | @filter.filter |
|---|
| 431 | | end |
|---|
| 432 | | end |
|---|
| 433 | | |
|---|
| 434 | | class BeforeFilterProxy < FilterProxy #:nodoc: |
|---|
| 435 | | def type |
|---|
| 436 | | :before |
|---|
| 437 | | end |
|---|
| 438 | | |
|---|
| 439 | | def run(controller) |
|---|
| 440 | | # only filters returning false are halted. |
|---|
| 441 | | @filter.call(controller) |
|---|
| 442 | | if controller.send!(:performed?) |
|---|
| 443 | | controller.send!(:halt_filter_chain, @filter, :rendered_or_redirected) |
|---|
| 444 | | end |
|---|
| 445 | | end |
|---|
| 446 | | |
|---|
| 447 | | def call(controller) |
|---|
| 448 | | yield unless run(controller) |
|---|
| 449 | | end |
|---|
| 450 | | end |
|---|
| 451 | | |
|---|
| 452 | | class AfterFilterProxy < FilterProxy #:nodoc: |
|---|
| 453 | | def type |
|---|
| 454 | | :after |
|---|
| 455 | | end |
|---|
| 456 | | |
|---|
| 457 | | def run(controller) |
|---|
| 458 | | @filter.call(controller) |
|---|
| 459 | | end |
|---|
| 460 | | |
|---|
| 461 | | def call(controller) |
|---|
| 462 | | yield |
|---|
| 463 | | run(controller) |
|---|
| 464 | | end |
|---|
| 465 | | end |
|---|
| 466 | | |
|---|
| 467 | | class SymbolFilter < Filter #:nodoc: |
|---|
| 468 | | def call(controller, &block) |
|---|
| 469 | | controller.send!(@filter, &block) |
|---|
| 470 | | end |
|---|
| 471 | | end |
|---|
| 472 | | |
|---|
| 473 | | class ProcFilter < Filter #:nodoc: |
|---|
| 474 | | def call(controller) |
|---|
| 475 | | @filter.call(controller) |
|---|
| 476 | | rescue LocalJumpError # a yield from a proc... no no bad dog. |
|---|
| 477 | | raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.') |
|---|
| 478 | | end |
|---|
| 479 | | end |
|---|
| 480 | | |
|---|
| 481 | | class ProcWithCallFilter < Filter #:nodoc: |
|---|
| 482 | | def call(controller, &block) |
|---|
| 483 | | @filter.call(controller, block) |
|---|
| 484 | | rescue LocalJumpError # a yield from a proc... no no bad dog. |
|---|
| 485 | | raise(ActionControllerError, 'Cannot yield from a Proc type filter. The Proc must take two arguments and execute #call on the second argument.') |
|---|
| 486 | | end |
|---|
| 487 | | end |
|---|
| 488 | | |
|---|
| 489 | | class MethodFilter < Filter #:nodoc: |
|---|
| 490 | | def call(controller, &block) |
|---|
| 491 | | @filter.call(controller, &block) |
|---|
| 492 | | end |
|---|
| 493 | | end |
|---|
| 494 | | |
|---|
| 495 | | class ClassFilter < Filter #:nodoc: |
|---|
| 496 | | def call(controller, &block) |
|---|
| 497 | | @filter.filter(controller, &block) |
|---|
| 498 | | end |
|---|
| 499 | | end |
|---|
| 500 | | |
|---|
| 501 | | class ClassBeforeFilter < Filter #:nodoc: |
|---|
| 502 | | def call(controller, &block) |
|---|
| 503 | | @filter.before(controller) |
|---|
| 504 | | end |
|---|
| 505 | | end |
|---|
| 506 | | |
|---|
| 507 | | class ClassAfterFilter < Filter #:nodoc: |
|---|
| 508 | | def call(controller, &block) |
|---|
| 509 | | @filter.after(controller) |
|---|
| 510 | | end |
|---|
| 511 | | end |
|---|
| 512 | | |
|---|
| 513 | | protected |
|---|
| 514 | | def append_filter_to_chain(filters, filter_type = :around, &block) |
|---|
| 515 | | pos = find_filter_append_position(filters, filter_type) |
|---|
| 516 | | update_filter_chain(filters, filter_type, pos, &block) |
|---|
| 517 | | end |
|---|
| 518 | | |
|---|
| 519 | | def prepend_filter_to_chain(filters, filter_type = :around, &block) |
|---|
| 520 | | pos = find_filter_prepend_position(filters, filter_type) |
|---|
| 521 | | update_filter_chain(filters, filter_type, pos, &block) |
|---|
| 522 | | end |
|---|
| 523 | | |
|---|
| 524 | | def update_filter_chain(filters, filter_type, pos, &block) |
|---|
| 525 | | new_filters = create_filters(filters, filter_type, &block) |
|---|
| 526 | | new_chain = filter_chain.insert(pos, new_filters).flatten |
|---|
| 527 | | write_inheritable_attribute('filter_chain', new_chain) |
|---|
| 528 | | end |
|---|
| 529 | | |
|---|
| 530 | | def find_filter_append_position(filters, filter_type) |
|---|
| 531 | | # appending an after filter puts it at the end of the call chain |
|---|
| 532 | | # before and around filters go before the first after filter in the chain |
|---|
| 533 | | unless filter_type == :after |
|---|
| 534 | | filter_chain.each_with_index do |f,i| |
|---|
| 535 | | return i if f.after? |
|---|
| 536 | | end |
|---|
| 537 | | end |
|---|
| 538 | | return -1 |
|---|
| 539 | | end |
|---|
| 540 | | |
|---|
| 541 | | def find_filter_prepend_position(filters, filter_type) |
|---|
| 542 | | # prepending a before or around filter puts it at the front of the call chain |
|---|
| 543 | | # after filters go before the first after filter in the chain |
|---|
| 544 | | if filter_type == :after |
|---|
| 545 | | filter_chain.each_with_index do |f,i| |
|---|
| 546 | | return i if f.after? |
|---|
| 547 | | end |
|---|
| 548 | | return -1 |
|---|
| 549 | | end |
|---|
| 550 | | return 0 |
|---|
| 551 | | end |
|---|
| 552 | | |
|---|
| 553 | | def create_filters(filters, filter_type, &block) #:nodoc: |
|---|
| 554 | | filters, conditions = extract_conditions(filters, &block) |
|---|
| 555 | | filters.map! { |filter| find_or_create_filter(filter, filter_type) } |
|---|
| 556 | | update_conditions(filters, conditions) |
|---|
| 557 | | filters |
|---|
| 558 | | end |
|---|
| 559 | | |
|---|
| 560 | | def find_or_create_filter(filter, filter_type) |
|---|
| 561 | | if found_filter = find_filter(filter) { |f| f.type == filter_type } |
|---|
| 562 | | found_filter |
|---|
| 563 | | else |
|---|
| 564 | | f = class_for_filter(filter, filter_type).new(filter) |
|---|
| 565 | | # apply proxy to filter if necessary |
|---|
| 566 | | case filter_type |
|---|
| 567 | | when :before |
|---|
| 568 | | BeforeFilterProxy.new(f) |
|---|
| 569 | | when :after |
|---|
| 570 | | AfterFilterProxy.new(f) |
|---|
| 571 | | else |
|---|
| 572 | | f |
|---|
| 573 | | end |
|---|
| 574 | | end |
|---|
| 575 | | end |
|---|
| 576 | | |
|---|
| 577 | | # The determination of the filter type was once done at run time. |
|---|
| 578 | | # This method is here to extract as much logic from the filter run time as possible |
|---|
| 579 | | def class_for_filter(filter, filter_type) #:nodoc: |
|---|
| 580 | | case |
|---|
| 581 | | when filter.is_a?(Symbol) |
|---|
| 582 | | SymbolFilter |
|---|
| 583 | | when filter.respond_to?(:call) |
|---|
| 584 | | if filter.is_a?(Method) |
|---|
| 585 | | MethodFilter |
|---|
| 586 | | else |
|---|
| 587 | | case filter.arity |
|---|
| 588 | | when 1; ProcFilter |
|---|
| 589 | | when 2; ProcWithCallFilter |
|---|
| 590 | | else raise ArgumentError, 'Filter blocks must take one or two arguments.' |
|---|
| 591 | | end |
|---|
| 592 | | end |
|---|
| 593 | | when filter.respond_to?(:filter) |
|---|
| 594 | | ClassFilter |
|---|
| 595 | | when filter.respond_to?(:before) && filter_type == :before |
|---|
| 596 | | ClassBeforeFilter |
|---|
| 597 | | when filter.respond_to?(:after) && filter_type == :after |
|---|
| 598 | | ClassAfterFilter |
|---|
| 599 | | else |
|---|
| 600 | | raise(ActionControllerError, 'A filter must be a Symbol, Proc, Method, or object responding to filter, after or before.') |
|---|
| 601 | | end |
|---|
| 602 | | end |
|---|
| 603 | | |
|---|
| 604 | | def extract_conditions(*filters, &block) #:nodoc: |
|---|
| 605 | | filters.flatten! |
|---|
| 606 | | conditions = filters.extract_options! |
|---|
| 607 | | filters << block if block_given? |
|---|
| 608 | | return filters, conditions |
|---|
| 609 | | end |
|---|
| 610 | | |
|---|
| 611 | | def update_conditions(filters, conditions) |
|---|
| 612 | | return if conditions.empty? |
|---|
| 613 | | if conditions[:only] |
|---|
| 614 | | write_inheritable_hash('included_actions', condition_hash(filters, conditions[:only])) |
|---|
| 615 | | elsif conditions[:except] |
|---|
| 616 | | write_inheritable_hash('excluded_actions', condition_hash(filters, conditions[:except])) |
|---|
| 617 | | end |
|---|
| 618 | | end |
|---|
| 619 | | |
|---|
| 620 | | def condition_hash(filters, *actions) |
|---|
| 621 | | actions = actions.flatten.map(&:to_s) |
|---|
| 622 | | filters.inject({}) { |h,f| h.update( f => (actions.blank? ? nil : actions)) } |
|---|
| 623 | | end |
|---|
| 624 | | |
|---|
| 625 | | def skip_filter_in_chain(*filters, &test) #:nodoc: |
|---|
| 626 | | filters, conditions = extract_conditions(filters) |
|---|
| 627 | | filters.map! { |f| block_given? ? find_filter(f, &test) : find_filter(f) } |
|---|
| 628 | | filters.compact! |
|---|
| 629 | | |
|---|
| 630 | | if conditions.empty? |
|---|
| 631 | | delete_filters_in_chain(filters) |
|---|
| 632 | | else |
|---|
| 633 | | remove_actions_from_included_actions!(filters,conditions[:only] || []) |
|---|
| 634 | | conditions[:only], conditions[:except] = conditions[:except], conditions[:only] |
|---|
| 635 | | update_conditions(filters,conditions) |
|---|
| 636 | | end |
|---|
| 637 | | end |
|---|
| 638 | | |
|---|
| 639 | | def remove_actions_from_included_actions!(filters,*actions) |
|---|
| 640 | | actions = actions.flatten.map(&:to_s) |
|---|
| 641 | | updated_hash = filters.inject(read_inheritable_attribute('included_actions')||{}) do |hash,filter| |
|---|
| 642 | | ia = (hash[filter] || []) - actions |
|---|
| 643 | | ia.empty? ? hash.delete(filter) : hash[filter] = ia |
|---|
| 644 | | hash |
|---|
| 645 | | end |
|---|
| 646 | | write_inheritable_attribute('included_actions', updated_hash) |
|---|
| 647 | | end |
|---|
| 648 | | |
|---|
| 649 | | def delete_filters_in_chain(filters) #:nodoc: |
|---|
| 650 | | write_inheritable_attribute('filter_chain', filter_chain.reject { |f| filters.include?(f) }) |
|---|
| 651 | | end |
|---|
| 652 | | |
|---|
| 653 | | def filter_responds_to_before_and_after(filter) #:nodoc: |
|---|
| 654 | | filter.respond_to?(:before) && filter.respond_to?(:after) |
|---|
| 655 | | end |
|---|
| 656 | | |
|---|
| 657 | | def proxy_before_and_after_filter(filter) #:nodoc: |
|---|
| 658 | | return filter unless filter_responds_to_before_and_after(filter) |
|---|
| 659 | | Proc.new do |controller, action| |
|---|
| 660 | | filter.before(controller) |
|---|
| 661 | | |
|---|
| 662 | | if controller.send!(:performed?) |
|---|
| 663 | | controller.send!(:halt_filter_chain, filter, :rendered_or_redirected) |
|---|
| 664 | | else |
|---|
| 665 | | begin |
|---|
| 666 | | action.call |
|---|
| 667 | | ensure |
|---|
| 668 | | filter.after(controller) |
|---|
| 669 | | end |
|---|
| 670 | | end |
|---|
| 671 | | end |
|---|
| 672 | | end |
|---|
| | 544 | filter_chain.select(&:after?).map(&:method) |
|---|
| | 545 | end |
|---|
| 695 | | |
|---|
| 696 | | def call_filters(chain, index, nesting) |
|---|
| 697 | | index = run_before_filters(chain, index, nesting) |
|---|
| 698 | | aborted = @before_filter_chain_aborted |
|---|
| 699 | | perform_action_without_filters unless performed? || aborted |
|---|
| 700 | | return index if nesting != 0 || aborted |
|---|
| 701 | | run_after_filters(chain, index) |
|---|
| 702 | | end |
|---|
| 703 | | |
|---|
| 704 | | def skip_excluded_filters(chain, index) |
|---|
| 705 | | while (filter = chain[index]) && self.class.filter_excluded_from_action?(filter, action_name) |
|---|
| 706 | | index = index.next |
|---|
| 707 | | end |
|---|
| 708 | | [filter, index] |
|---|
| 709 | | end |
|---|
| 710 | | |
|---|
| 711 | | def run_before_filters(chain, index, nesting) |
|---|
| 712 | | while chain[index] |
|---|
| 713 | | filter, index = skip_excluded_filters(chain, index) |
|---|
| 714 | | break unless filter # end of call chain reached |
|---|
| 715 | | |
|---|
| 716 | | case filter.type |
|---|
| 717 | | when :before |
|---|
| 718 | | filter.run(self) # invoke before filter |
|---|
| | 567 | def call_filters(chain, index, nesting) |
|---|
| | 568 | index = run_before_filters(chain, index, nesting) |
|---|
| | 569 | aborted = @before_filter_chain_aborted |
|---|
| | 570 | perform_action_without_filters unless performed? || aborted |
|---|
| | 571 | return index if nesting != 0 || aborted |
|---|
| | 572 | run_after_filters(chain, index) |
|---|
| | 573 | end |
|---|
| | 574 | |
|---|
| | 575 | def run_before_filters(chain, index, nesting) |
|---|
| | 576 | while chain[index] |
|---|
| | 577 | filter, index = chain[index], index |
|---|
| | 578 | break unless filter # end of call chain reached |
|---|
| | 579 | |
|---|
| | 580 | case filter |
|---|
| | 581 | when BeforeFilter |
|---|
| | 582 | filter.call(self) # invoke before filter |
|---|
| | 583 | index = index.next |
|---|
| | 584 | break if @before_filter_chain_aborted |
|---|
| | 585 | when AroundFilter |
|---|
| | 586 | yielded = false |
|---|
| | 587 | |
|---|
| | 588 | filter.call(self) do |
|---|
| | 589 | yielded = true |
|---|
| | 590 | # all remaining before and around filters will be run in this call |
|---|
| | 591 | index = call_filters(chain, index.next, nesting.next) |
|---|
| | 592 | end |
|---|
| | 593 | |
|---|
| | 594 | halt_filter_chain(filter, :did_not_yield) unless yielded |
|---|
| | 595 | |
|---|
| | 596 | break |
|---|
| | 597 | else |
|---|
| | 598 | break # no before or around filters left |
|---|
| | 599 | end |
|---|
| | 600 | end |
|---|
| | 601 | |
|---|
| | 602 | index |
|---|
| | 603 | end |
|---|
| | 604 | |
|---|
| | 605 | def run_after_filters(chain, index) |
|---|
| | 606 | seen_after_filter = false |
|---|
| | 607 | |
|---|
| | 608 | while chain[index] |
|---|
| | 609 | filter, index = chain[index], index |
|---|
| | 610 | break unless filter # end of call chain reached |
|---|
| | 611 | |
|---|
| | 612 | case filter |
|---|
| | 613 | when AfterFilter |
|---|
| | 614 | seen_after_filter = true |
|---|
| | 615 | filter.call(self) # invoke after filter |
|---|
| | 616 | else |
|---|
| | 617 | # implementation error or someone has mucked with the filter chain |
|---|
| | 618 | raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter |
|---|
| | 619 | end |
|---|
| | 620 | |
|---|