Permalink
Browse files

Rename all action callbacks from *_filter to *_action

  • Loading branch information...
dhh committed Dec 7, 2012
1 parent c205284 commit 9d62e04838f01f5589fa50b0baa480d60c815e2c
@@ -1,4 +1,31 @@
## Rails 4.0.0 (unreleased) ##
* Rename all action callbacks from *_filter to *_action to avoid the misconception that these
callbacks are only suited for transforming or halting the response. With the new style,
it's more inviting to use them as they were intended, like setting shared ivars for views.
Example:
class PeopleController < ActionController::Base
before_action :set_person, except: [ :index, :new, :create ]
before_action :ensure_permission, only: [ :edit, :update ]
...
private
def set_person
@person = current_account.people.find(params[:id])
end
def ensure_permission
current_person.change_change?(@person)

This comment has been minimized.

@garethrees

garethrees Dec 7, 2012

Contributor

Should that read current_person.can_change?(@person)?

This comment has been minimized.

@dhh

dhh via email Dec 7, 2012

Member

This comment has been minimized.

@garethrees

garethrees Dec 7, 2012

Contributor

No problem, nice change 👍

end
end
The old *_filter methods still work with no deprecation notice.
*DHH*
* Add :if / :unless conditions to fragment cache:
<%= cache @model, if: some_condition(@model) do %>
@@ -40,18 +40,21 @@ def _normalize_callback_option(options, from, to) # :nodoc:
end
end
# Skip before, after, and around filters matching any of the names
# Skip before, after, and around action callbacks matching any of the names
# Aliased as skip_filter.
#
# ==== Parameters
# * <tt>names</tt> - A list of valid names that could be used for
# callbacks. Note that skipping uses Ruby equality, so it's
# impossible to skip a callback defined using an anonymous proc
# using #skip_filter
def skip_filter(*names)
skip_before_filter(*names)
skip_after_filter(*names)
skip_around_filter(*names)
def skip_action_callback(*names)
skip_before_action(*names)
skip_after_action(*names)
skip_around_action(*names)
end
alias_method :skip_filter, :skip_action_callback
# Take callback names and an optional callback proc, normalize them,
# then call the block with each callback. This allows us to abstract
@@ -75,119 +78,138 @@ def _insert_callbacks(callbacks, block = nil)
end
##
# :method: before_filter
# :method: before_action
#
# :call-seq: before_filter(names, block)
# :call-seq: before_action(names, block)
#
# Append a before filter. See _insert_callbacks for parameter details.
# Append a callback before actions. See _insert_callbacks for parameter details.
# Aliased as before_filter.
##
# :method: prepend_before_filter
# :method: prepend_before_action
#
# :call-seq: prepend_before_filter(names, block)
# :call-seq: prepend_before_action(names, block)
#
# Prepend a before filter. See _insert_callbacks for parameter details.
# Prepend a callback before actions. See _insert_callbacks for parameter details.
# Aliased as prepend_before_action.
##
# :method: skip_before_filter
# :method: skip_before_action
#
# :call-seq: skip_before_filter(names)
# :call-seq: skip_before_action(names)
#
# Skip a before filter. See _insert_callbacks for parameter details.
# Skip a callback before actions. See _insert_callbacks for parameter details.
# Aliased as skip_before_filter.
##
# :method: append_before_filter
# :method: append_before_action
#
# :call-seq: append_before_filter(names, block)
# :call-seq: append_before_action(names, block)
#
# Append a before filter. See _insert_callbacks for parameter details.
# Append a callback before actions. See _insert_callbacks for parameter details.
# Aliased as append_before_filter.
##
# :method: after_filter
# :method: after_action
#
# :call-seq: after_filter(names, block)
# :call-seq: after_action(names, block)
#
# Append an after filter. See _insert_callbacks for parameter details.
# Append a callback after actions. See _insert_callbacks for parameter details.
# Aliased as after_filter.
##
# :method: prepend_after_filter
# :method: prepend_after_action
#
# :call-seq: prepend_after_filter(names, block)
# :call-seq: prepend_after_action(names, block)
#
# Prepend an after filter. See _insert_callbacks for parameter details.
# Prepend a callback after actions. See _insert_callbacks for parameter details.
# Aliased as prepend_after_filter.
##
# :method: skip_after_filter
# :method: skip_after_action
#
# :call-seq: skip_after_filter(names)
# :call-seq: skip_after_action(names)
#
# Skip an after filter. See _insert_callbacks for parameter details.
# Skip a callback after actions. See _insert_callbacks for parameter details.
# Aliased as skip_after_filter.
##
# :method: append_after_filter
# :method: append_after_action
#
# :call-seq: append_after_filter(names, block)
# :call-seq: append_after_action(names, block)
#
# Append an after filter. See _insert_callbacks for parameter details.
# Append a callback after actions. See _insert_callbacks for parameter details.
# Aliased as append_after_filter.
##
# :method: around_filter
# :method: around_action
#
# :call-seq: around_filter(names, block)
# :call-seq: around_action(names, block)
#
# Append an around filter. See _insert_callbacks for parameter details.
# Append a callback around actions. See _insert_callbacks for parameter details.
# Aliased as around_filter.
##
# :method: prepend_around_filter
# :method: prepend_around_action
#
# :call-seq: prepend_around_filter(names, block)
# :call-seq: prepend_around_action(names, block)
#
# Prepend an around filter. See _insert_callbacks for parameter details.
# Prepend a callback around actions. See _insert_callbacks for parameter details.
# Aliased as prepend_around_filter.
##
# :method: skip_around_filter
# :method: skip_around_action
#
# :call-seq: skip_around_filter(names)
# :call-seq: skip_around_action(names)
#
# Skip an around filter. See _insert_callbacks for parameter details.
# Skip a callback around actions. See _insert_callbacks for parameter details.
# Aliased as skip_around_filter.
##
# :method: append_around_filter
# :method: append_around_action
#
# :call-seq: append_around_filter(names, block)
# :call-seq: append_around_action(names, block)
#
# Append an around filter. See _insert_callbacks for parameter details.
# Append a callback around actions. See _insert_callbacks for parameter details.
# Aliased as append_around_filter.
# set up before_filter, prepend_before_filter, skip_before_filter, etc.
# set up before_action, prepend_before_action, skip_before_action, etc.
# for each of before, after, and around.
[:before, :after, :around].each do |filter|
[:before, :after, :around].each do |callback|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
# Append a before, after or around filter. See _insert_callbacks
# Append a before, after or around callback. See _insert_callbacks
# for details on the allowed parameters.
def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before, name, options)
end # end
end # end
def #{callback}_action(*names, &blk) # def before_action(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, :#{callback}, name, options) # set_callback(:process_action, :before, name, options)
end # end
end # end
# Prepend a before, after or around filter. See _insert_callbacks
alias_method :#{callback}_filter, :#{callback}_action
# Prepend a before, after or around callback. See _insert_callbacks
# for details on the allowed parameters.
def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
end # end
end # end
def prepend_#{callback}_action(*names, &blk) # def prepend_before_action(*names, &blk)
_insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
set_callback(:process_action, :#{callback}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
end # end
end # end
alias_method :prepend_#{callback}_filter, :prepend_#{callback}_action
# Skip a before, after or around filter. See _insert_callbacks
# Skip a before, after or around callback. See _insert_callbacks
# for details on the allowed parameters.
def skip_#{filter}_filter(*names) # def skip_before_filter(*names)
_insert_callbacks(names) do |name, options| # _insert_callbacks(names) do |name, options|
skip_callback(:process_action, :#{filter}, name, options) # skip_callback(:process_action, :before, name, options)
end # end
end # end
# *_filter is the same as append_*_filter
alias_method :append_#{filter}_filter, :#{filter}_filter # alias_method :append_before_filter, :before_filter
def skip_#{callback}_action(*names) # def skip_before_action(*names)
_insert_callbacks(names) do |name, options| # _insert_callbacks(names) do |name, options|
skip_callback(:process_action, :#{callback}, name, options) # skip_callback(:process_action, :before, name, options)
end # end
end # end
alias_method :skip_#{callback}_filter, :skip_#{callback}_action
# *_action is the same as append_*_action
alias_method :append_#{callback}_action, :#{callback}_action # alias_method :append_before_action, :before_action
alias_method :append_#{callback}_filter, :#{callback}_action # alias_method :append_before_filter, :before_action
RUBY_EVAL
end
end
@@ -84,11 +84,11 @@ def setup
end
class Callback3 < ControllerWithCallbacks
before_filter do |c|
before_action do |c|
c.instance_variable_set("@text", "Hello world")
end
after_filter do |c|
after_action do |c|
c.instance_variable_set("@second", "Goodbye")
end
@@ -114,8 +114,8 @@ def setup
end
class CallbacksWithConditions < ControllerWithCallbacks
before_filter :list, :only => :index
before_filter :authenticate, :except => :index
before_action :list, :only => :index
before_action :authenticate, :except => :index
def index
self.response_body = @list.join(", ")
@@ -202,7 +202,7 @@ def setup
end
class ChangedConditions < Callback2
before_filter :first, :only => :index
before_action :first, :only => :index
def not_index
@text ||= nil

34 comments on commit 9d62e04

@jeremy

This comment has been minimized.

Member

jeremy replied Dec 7, 2012

👍

@luizkowalski

This comment has been minimized.

luizkowalski replied Dec 7, 2012

nice one!

@signalnerve

This comment has been minimized.

Contributor

signalnerve replied Dec 7, 2012

Changing this to action makes a lot more sense for people learning these things (like me) in understanding that there's a verb going on here (as in :authenticate as an action). Thanks for this.
👍

@josh

This comment has been minimized.

Member

josh replied Dec 7, 2012

I dig it. ⚡️

@natebird

This comment has been minimized.

natebird replied Dec 7, 2012

Small changes like this is Rails that make it better semantically are what keep me using it. Great change.

@giedriusr

This comment has been minimized.

giedriusr replied Dec 7, 2012

👍

@wildchild

This comment has been minimized.

Contributor

wildchild replied Dec 7, 2012

I miss Merb's before and after.

@milushov

This comment has been minimized.

milushov replied Dec 7, 2012

👍

@dvarelap

This comment has been minimized.

dvarelap replied Dec 7, 2012

nice!

@AlexanderPavlenko

This comment has been minimized.

AlexanderPavlenko replied Dec 7, 2012

Does the return value (true or false) still control the flow?
It looks more natural for me to expect method with such a name before_action to raise exception or call some another method like halt!.

@glongman

This comment has been minimized.

glongman replied Dec 7, 2012

works for me

@fxn

This comment has been minimized.

Member

fxn replied Dec 7, 2012

The return value was taken into account in the early days, but it's been a long time since filters are halted by rendering or redirecting.

@3den

This comment has been minimized.

3den replied Dec 7, 2012

@dhh why not just before :action, :do_something?

@dhh

This comment has been minimized.

Member

dhh replied Dec 7, 2012

Marcelo, because that's terribly ambiguous. before what? before rendering? before :authenticate "before authenticate"? before_action :authenticate is much clearer.

@mislav

This comment has been minimized.

Member

mislav replied Dec 7, 2012

I don't like the example in the documentation:

def set_person
  @person = current_account.people.find(params[:id])
end

Having a separate method just to set an ivar is an antipattern. I don't want to teach this to less experienced developer.

A much better implementation would be: (although, then it quits being an example for before_action)

def current_person
  @current_person ||= current_account.people.find(params[:id])
end
@qingwang

This comment has been minimized.

qingwang replied Dec 7, 2012

before_filter did confuse me a little bit at the beginning. Nice change. I was thinking before_do , after_do .

@dhh

This comment has been minimized.

Member

dhh replied Dec 7, 2012

@Dorian

This comment has been minimized.

Contributor

Dorian replied Dec 7, 2012

Nice! Great to see that you can always change the API even if it's a popular method.

@3den

This comment has been minimized.

3den replied Dec 7, 2012

Hi @dhh, Thanks for your reply. One of the best thinks about rails is it clean and easy to read syntax. For sure _action is more meaningful than _filter but both add redundancy to de code. In plain english before :save, :calculate_total reads much cleaner than before_action :save, :calculate_total.

@dhh

This comment has been minimized.

Member

dhh replied Dec 7, 2012

@Dorian

This comment has been minimized.

Contributor

Dorian replied Dec 7, 2012

@3den: Maybe before and after are too general words to be used here (they may be used in action names) but renaming to before/after would be better.

@eavgerinos

This comment has been minimized.

Contributor

eavgerinos replied Dec 7, 2012

👍

@hron84

This comment has been minimized.

hron84 replied Dec 7, 2012

👍

@matthewrobertson

This comment has been minimized.

Contributor

matthewrobertson replied Dec 7, 2012

I feel 😐 about this. I think it would have been nice if it were called before_action from the beginning of time but I dunno if you actually get a lot of milage from the principle of least surprise . As someone thats been coding rails for a while I'm going to be like: "WTF is a before_action!?" If it aint broke, why fix it?

@muescha

This comment has been minimized.

muescha replied Dec 7, 2012

why not an alias method which inform about the removing version - dont take all the old legacy code with every version. better clean it. too much similar methods also confuses newcomers

alias_deprecated_method 4.1, :old, :new

@steveklabnik

This comment has been minimized.

Member

steveklabnik replied Dec 7, 2012

@muescha because it is not deprecated at this time. Just introducing a new name. If it's significantly nicer, we'll deprecate the old one.

@PikachuEXE

This comment has been minimized.

Contributor

PikachuEXE replied Dec 8, 2012

This name makes much more sense! 👍

@ck3g

This comment has been minimized.

Contributor

ck3g replied Dec 8, 2012

👍

@hpyhacking

This comment has been minimized.

hpyhacking replied Dec 13, 2012

对代码有洁癖

@knwang

This comment has been minimized.

knwang replied Dec 15, 2012

Makes sense. +1

@JurgenJocubeit

This comment has been minimized.

JurgenJocubeit replied Jan 8, 2013

I think _action is self-explanatory. It'd be nice though if we had a backport for 3.2.10, just one more thing we need to remember to do for the upgrade. Before you all retaliate I know before_filter and after_filter aren't deprecated yet, but most will want to use the new syntax, so moving to _action will become the norm.

@carlosantoniodasilva

This comment has been minimized.

Member

carlosantoniodasilva replied Jan 8, 2013

@MeetDom sorry, no new features are backported to 3.2, only bug fixes. But it should be dead easy to alias the methods before/after filter in your application controller, and start using as before/after action.

@examplecode

This comment has been minimized.

examplecode replied May 26, 2014

good job ,it's more appropriate

@liuganggang

This comment has been minimized.

liuganggang replied Jun 18, 2014

长姿势了:+1

Please sign in to comment.