Redefining before_validation for an ActiveRecord model


I'm struggling more then a day now to try to write a simple plugin.

Let me explain what the plugin should do. Consider a table called categories that looks like:

create_table :categories do |t|      t.column :id, :integer      t.column :categorizable_type, :string, :null => false      t.column :categorizable_id, :integer, :null => false, :references => nil      t.column :category_name, :integer, :null => false end

with model:

class Category < ActiveRecord::Base belongs_to :categorizable, :polymorphic => true validates_presence_of :categorizable_type, :categorizable_id end

Then for example a product is categorizable, table and model of product look like this:

create_table :products do |t|      t.column :id, :integer      t.column :code, :string end

class Product < ActiveRecord::Base   has_many :categories, :as => :categorizable end

So products are categorizable. Now I want to define a model product_categories that contains all categories for products.

The definition of product_categories is: class ProductCategory < Category     set_scope :categorizable_type, "Product" end

Notice the 'set_scope' definition. This is the plugin I am writing (called ScopedModel) and the idea is that when a model gets the set_scope definition, automatically the categorizable_type should be on 'Product' for all manipulations. For example:

ProductCategory.find(:all) should result in:

select * from categories where categorizable_type='Product'

ProductCategory.create!(category_name => 'some_name') should result in a record being created where categorizable_type has value 'Product'.

So all operations on ProductCategory should result in making sure that everything is qualified with 'categorizable_type = 'Product'. Until now I have been able to make it work for find, but I can't let it work for create, update ,...

My working plugin code until now is:

ActiveRecord::Base.send :include, ScopedModel

module ScopedModel     def self.included(base)        base.class_eval do             class << self                 alias_method :orig_find_every, :find_every

                def set_scope(attribute,value)                     @model_scope ||= {}                     @model_scope[attribute] = value                 end

                # redefine find                 private                 def find_every(*args)                     @find_option =                     @model_scope ||= {}                     @model_scope.each_key do |attribute|                         value = @model_scope[attribute]                         @find_option[:conditions] = "#{attribute} = '#{value}'"                     end                     with_scope :find => (@find_option) do                         orig_find_every(*args)                     end                 end             end         end     end end

(I borrowed the code from the excellent HOWTO, see

So the find method automatically adds the scope qualification by adding it to the find of the class's singleton class. For the create, update, I want to use the 'before_validation' method. If I put next in my ProductCategory model:

def before_validation   self.categorizable_type = 'Product' end

Problem is that I should be able to define this before_validation in the plugin in the singleton class for product_category. And I tried everything but nothing works. The code in the plugin should be something like:

alias_method :orig_before_validation, :before_validation def before_validation   @model_scope ||= {}   @model_scope.each_key do |attribute|      self.attribute = @model_scope[attribute]   end   orig_before_validation end

Problem is that before_validation is mixed_in in ActiveRecord::Base and also that it should work on an instance and not at class_level, while my definition of set_scope is at (singleton) class level,

Hope that anyone can shed some light on this problem.

Thanks and Regards Wim