Modules vs. Classes and their influence on descendants of ActiveRecord::Base
Here's a Ruby OO head scratcher for ya, brought about by 开发者_StackOverflowthis Rails scenario:
class Product < ActiveRecord::Base
has_many(:prices)
# define private helper methods
end
module PrintProduct
attr_accessor(:isbn)
# override methods in ActiveRecord::Base
end
class Book < Product
include PrintProduct
end
Product is the base class of all products. Books are kept in the products table via STI. The PrintProduct module brings some common behavior and state to descendants of Product. Book is used inside fields_for blocks in views. This works for me, but I found some odd behavior:
- After form submission, inside my controller, if I call a method on a book that is defined in
PrintProduct, and that method calls a helper method defined inProduct, which in turn calls thepricesmethod defined byhas_many, I'll get an error complaining thatBook#pricesis not found.
Why is that? Book is a direct descendant of Product!
More interesting is the following..
As I developed this hierarchy PrintProduct started to become more of an abstract ActiveRecord::Base, so I thought it prudent to redefine everything as such:
class Product < ActiveRecord::Base
end
class PrintProduct < Product
end
class Book < PrintProduct
end
All method definitions, etc. are the same. In this case, however, my web form won't load because the attributes defined by attr_accessor (which are "virtual attributes" referenced by the form but not persisted in the DB) aren't found. I'll get an error saying that there is no method Book#isbn. Why is that?? I can't see a reason why the attr_accessor attributes are not found inside my form's fields_for block when PrintProduct is a class, but they are found when PrintProduct is a Module.
Any insight would be appreciated. I'm dying to know why these errors are occurring!
You might have better luck delaying the attr_accessor call in PrintProduct until mixin-time:
module PrintProduct
def self.included(base)
base.attr_accessor :isbn
end
# other instance methods here
end
The problem is likely something to do with timing of the attr_accessor call and how that applies to modules mixed in. I'm not certain that the timing is defined by the Ruby spec, so it might vary betweeen implementations or versions.
加载中,请稍侯......
精彩评论