Difference between "class << anObject" and anObject.class_eval
I see the following code in the attribute_fu plugin:
module AttributeFu module Associations #:nodoc: def self.included(base) #:nodoc: base.class_eval do extend ClassMethods class << self; alias_method_chain :has_many, :association_option; end class_inheritable_accessor :managed_association_attributes write_inheritable_attribute :managed_association_attributes, [] after_update :save_managed_associations end end ... end end
When I try to replace
class << self; alias_method_chain :has_many, :association_option; end
with: alias_method_chain: has_many,: association_option?
I am getting the following error
/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method': undefined method `has_many' for class `ActiveRecord::Base' (NameError) from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/module/aliasing.rb:31:in `alias_method_chain' from /home/twong/git/physpace/vendor/plugins/attribute_fu/lib/attribute_fu/associations.rb:9:in `included'
I thought these two lines would do the same, but it looks like I'm wrong. Can someone explain my mistake?
source share
# init.rb ActiveRecord::Base.class_eval { include AttributeFu::Associations } module AttributeFu module Associations def self.included(base) # base == ActiveRecord::Base (the class) base.class_eval do # class_eval makes self == ActiveRecord::Base, and makes def define instance methods. extend ClassMethods # If has_many were an instance method, we could do this # alias_method_chain :has_many, :association_option; end # but it a class method, so we have to do the alias_method_chain on # the meta-class for ActiveRecord::Base, which is what class << self does. class << self; alias_method_chain :has_many, :association_option; end end end end end
Another way to play with this is to put it in the IRB:
class A ; end A.class_eval { puts self.inspect ; class << self ; puts self.inspect ; end }
see also
source share
In this case, self
doesn't mean anObject, it's more sugar.
class << self ... end
defines class methods for the enclosing object. Method alias_method_chain
is a method similar to what is. In this case, he aliases has_many
before has_many_without_association_options
and has_many_with_association_options
with has_many
. In your case, these are methods of the alias class, so you should use it in the scope of the class methods. This allows methods to be extended without much hassle.
Class methods are named, for example:
SomeThing.bar_method
whereas instance methods are called on class instances:
assoc = SomeThing.new assoc.foo_method
Relevant code:
class SomeThing def foo_method ... end class << self def bar_method ... end end end
in your case you have a module AttributeFu::Associations
. When included in the Foo class, it runs Foo.class_eval, which defines some of the instance attributes inside Foo, and runs a method alias_method_chain
inside the class's method scope ( class << self
).
There is also one extends ClassMethods
that should define:
def self.has_many_with_association_options ... end
or
class << self def has_many_with_association_options ... end end
source share