Wim Ceulemans
2008-Jan-25 10:07 UTC
Redefining before_validation for an ActiveRecord model
Hi 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 = Hash.new @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 http://www.railsforum.com/viewtopic.php?id=682 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 -- NEW on aXs GUARD: SSL VPN !! (contact your reseller for more info) --------------------------------------------------- aXs GUARD has completed security and anti-virus checks on this e-mail (http://www.axsguard.com) --------------------------------------------------- Able NV: ond.nr 0457.938.087 RPR Mechelen --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---