skip_before_filter (Do I need a lesson in modules/mixins?)

C

Cris Shupp

Gurus,

I am reading the O'Reilly book "Rails: Up and Running, 2nd Edition" and
the author told me to add the following line of code:

skip_before_filter :verify_authenticity_token

as follows:

class SlidesController < ApplicationController
skip_before_filter :verify_authenticity_token
...

This stopped me dead in my tracks as I realized I had no idea what was
going on. I am using Aptana (Eclipse) and so it can tell me that
skip_before_filter is defined in the module ClassMethods. I am assuming
that somehow this method (skip_before_filter) is mixed in?

The implementation is:
def skip_before_filter(*filters)
filter_chain.skip_filter_in_chain(*filters, &:before?)
end

What is *filters? Did I miss this in my 'Learning Ruby' book?

Anyway, I guessed that I was calling the method 'skip_before_filter'
sometime during my controller's construction. So I built a toy to
validate as follows:
####################BEGIN
test.rb###############################################
module Test
def call_me
puts "Mixin called"
end
end
module Test2
def call_me
puts "second mixin called"
end
end

class Tester
include Test, Test2
#call_me() #this call fails. This blows my theory...

def initialize
super
call_me()# this call works, but how would I call the other one?
#Test2::call_me()#this call fails
puts "A tester was built"
end

end

Tester.new
########################################END test.rb###########

output is:
Mixin called
A tester was built


Thanks for your help with my questions.

Cris
 
R

Ryan Davis

I am reading the O'Reilly book "Rails: Up and Running, 2nd Edition"
and

this is a ruby mailing list, not a ruby on rails mailing list. Please
post in the appropriate area.
 
M

Michael Guterl

Gurus,

I am reading the O'Reilly book "Rails: Up and Running, 2nd Edition" and
the author told me to add the following line of code:

skip_before_filter :verify_authenticity_token

as follows:

class SlidesController < ApplicationController
=C2=A0skip_before_filter :verify_authenticity_token
=C2=A0...

This stopped me dead in my tracks as I realized I had no idea what was
going on. =C2=A0I am using Aptana (Eclipse) and so it can tell me that
skip_before_filter is defined in the module ClassMethods. =C2=A0I am assu= ming
that somehow this method (skip_before_filter) is mixed in?

The implementation is:
=C2=A0 =C2=A0 =C2=A0def skip_before_filter(*filters)
=C2=A0 =C2=A0 =C2=A0 =C2=A0filter_chain.skip_filter_in_chain(*filters, &:= before?)
=C2=A0 =C2=A0 =C2=A0end

What is *filters? =C2=A0Did I miss this in my 'Learning Ruby' book?
This collects all of the arguments into an array called filters. You
can find more looking for "ruby splat" on google.
Anyway, I guessed that I was calling the method 'skip_before_filter'
sometime during my controller's construction. =C2=A0So I built a toy to
validate as follows:
####################BEGIN
test.rb###############################################
module Test
=C2=A0def call_me
=C2=A0 =C2=A0puts "Mixin called"
=C2=A0end
end
module Test2
=C2=A0def call_me
=C2=A0 =C2=A0puts "second mixin called"
=C2=A0end
end

class Tester
=C2=A0include Test, Test2
=C2=A0#call_me() #this call fails. =C2=A0This blows my theory...

=C2=A0def initialize
=C2=A0 =C2=A0super
=C2=A0 =C2=A0call_me()# this call works, but how would I call the other o= ne?
=C2=A0 =C2=A0#Test2::call_me()#this call fails
=C2=A0 =C2=A0puts "A tester was built"
=C2=A0end

end

Tester.new
########################################END test.rb###########

output is:
Mixin called
A tester was built

Rails uses a convention with modules similar to the following:

module FooBehaviors
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def foo
puts 42
end
end
end

class Bar
include FooBehaviors
foo
end

When FooBehaviors module is included, it also extends the including
class with the FooBehaviors::ClassMethods module. You can find out
more by looking at the differences between include and extend.

http://railstips.org/2009/5/15/include-verse-extend-in-ruby

Best,
Michael Guterl
 
7

7stud --

Cris said:
What is *filters? Did I miss this in my 'Learning Ruby' book?

def meth1(*args)
p args
end

meth1(1, 2, 3)

--output:--
[1, 2, 3]


def meth2(x, y, z)
puts x, y, z
end

args = [1, 2, 3]
meth2(*args)

--output:--
1
2
3


def meth3(x, y, *args)
p x, y, args
end

meth3(1, 2, 3, 4, 5, 6)

--output:--
1
2
[3, 4, 5, 6]
 
D

David Palm

this is a ruby mailing list, not a ruby on rails mailing list. Please
post in the appropriate area.

He asked a Ruby question, using Rails code as an example. Please don't be unfriendly.
 
C

Cris Shupp

When FooBehaviors module is included, it also extends the including
class with the FooBehaviors::ClassMethods module. You can find out
more by looking at the differences between include and extend.

http://railstips.org/2009/5/15/include-verse-extend-in-ruby

Best,
Michael Guterl


Michael,

Thanks for your response. Your url was helpful and by following the
inheritance tree I found the code that includes skip_before_filter:

Base.class_eval do
[ Filters, Layout, Benchmarking, Rescue, Flash, MimeResponds,
Helpers,
Cookies, Caching, Verification, Streaming, SessionManagement,
HttpAuthentication::Basic::ControllerMethods,
HttpAuthentication::Digest::ControllerMethods,
RecordIdentifier, RequestForgeryProtection, Translation
].each do |mod|
include mod
end

but I still feel like skip_before_filter is a dangling method call in
the following code:

class SlidesController < ApplicationController
skip_before_filter :verify_authenticity_token

I tried creating a simple example (using what your url illustrated) but
it does not work. Here is my toy The first 'call_me' invocation is
what I am assuming is equivalent to the skip_before_filter call:

module Test

def self.include(base)
base.extend(ClassMethods)
end

module ClassMethods

def call_me
puts "Class method"
end
end
end

module Test2
def call_me
puts "second mixin called"
end
end

class Tester
include Test, Test2
call_me()#toy.rb:23: undefined method `call_me' for Tester:Class
(NoMethodError)

def initialize
super
call_me()
puts "A tester was built"
end

end

Tester.new

I should mention that I am seeing these 'dangling' calls more and more
as I look through what the scaffolding generated so I would like a clue!

Thanks,

Cris
 
J

Jesús Gabriel y Galán

I tried creating a simple example (using what your url illustrated) but
it does not work. =A0Here is my toy =A0The first 'call_me' invocation is
what I am assuming is equivalent to the skip_before_filter call:

module Test

=A0def self.include(base)

def self.included(base)


irb(main):016:0> module Test
irb(main):017:1>
irb(main):018:1* def self.included(base)
irb(main):019:2> base.extend(ClassMethods)
irb(main):020:2> end
irb(main):021:1> module ClassMethods
irb(main):022:2> def call_me
irb(main):023:3> puts "Class method"
irb(main):024:3> end
irb(main):025:2> end
irb(main):026:1> end
=3D> nil
irb(main):027:0> class Tester
irb(main):028:1> include Test
irb(main):029:1> call_me
irb(main):030:1> end
Class method
=3D> nil

Hope this helps,

Jesus.
 
C

Cris Shupp

Well I can reproduce that in irb, but no it doesn't answer my question.

Anyone out there know the answer?

Thanks,

Cris
 
P

pharrington

I should mention that I am seeing these 'dangling' calls more and more
as I look through what the scaffolding generated so I would like a clue!

Thanks,

Cris

Is it the fact that the method calls aren't happening within another
method tripping you up? In Ruby, most everything happens at runtime,
class creation included. Also, everything's an object. So when
something like

class Foo; some_ish; end

happens, Ruby is creating a new class, and some_ish is just being run
in the instance of the Class that is being created. (well it *is* more
complicated than that, but that should be enough to help understand
whats going on?). Its really no different than attr_accessor and
friends.
 
C

Cris Shupp

No it is not the fact that the method call is not within another method
call that is tripping me up. It is that I cannot get it to work for me.

Consider the following code:
####################################
module Test

def self.include(base)
base.extend(ClassMethods)
end

module ClassMethods
def call_me
puts "Class method"
end
end
end

class Tester
include Test
call_me#toy.rb:23: undefined method `call_me' for
Tester:Class(NoMethodError)
end

Tester.new
###################################

yields the following results:
toy.rb:24: undefined local variable or method `call_me' for Tester:Class
(NameError)

Again I am assuming my 'call_me' is equivalent to my originally
referenced 'skip_before_filter'.

Thanks,

Cris
 
P

pharrington

No it is not the fact that the method call is not within another method
call that is tripping me up.  It is that I cannot get it to work for me..

Consider the following code:
####################################
module Test

  def self.include(base)
    base.extend(ClassMethods)
  end

  module ClassMethods
    def call_me
      puts "Class method"
    end
  end
end

class Tester
  include Test
 call_me#toy.rb:23: undefined method `call_me' for
Tester:Class(NoMethodError)
end

Tester.new
###################################

yields the following results:
toy.rb:24: undefined local variable or method `call_me' for Tester:Class
(NameError)

Again I am assuming my 'call_me' is equivalent to my originally
referenced 'skip_before_filter'.

Thanks,

Cris

Then I'm confused as to what you're still confused about? Jesus
already pointed out the typo: you need


def self.included(base)

versus
 
J

Jesús Gabriel y Galán

No it is not the fact that the method call is not within another method
call that is tripping me up. =A0It is that I cannot get it to work for me=
 
C

Cris Shupp

Thanks everyone (especially Michael and Jesus)!

I missed the missing 'd'. I put it in and it works!

And of course the 'd' is in the original code...

module ActionController #:nodoc:
module Filters #:nodoc:
def self.included(base)
base.class_eval do
extend ClassMethods
include ActionController::Filters::InstanceMethods
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,710
Latest member
bernietqt

Latest Threads

Top