views:

2020

answers:

4

Given a model

class BaseModel < ActiveRecord::Base
  validates_presence_of :parent_id
  before_save :frobnicate_widgets
end

and a derived model (the underlying database table has a type field - this is simple rails STI)

class DerivedModel < BaseModel
end

DerivedModel will in good OO fashion inherit all the behaviour from BaseModel, including the validates_presence_of :parent_id. I would like to turn the validation off for DerivedModel, and prevent the callback methods from firing, preferably without modifying or otherwise breaking BaseModel

What's the easiest and most robust way to do this?

A: 

I believe you'd have to rewrite the validate method in the derived model.

See: http://api.rubyonrails.org/classes/ActiveRecord/Validations.html

Can Berk Güder
The problem is, I'm not overriding those methods in AR::Base, so rewriting them in the derived model wouldn't affect it.
Orion Edwards
Hmm, you might be right. Why don't you try overriding validate in BaseModel instead of using class methods (validates_presence_of, etc.)?This way you can have conditional validations.
Can Berk Güder
+3  A: 

From poking around in the source (I'm currently on rails 1.2.6), the callbacks are relatively straightforward.

It turns out that the before_validation_on_create, before_save etc methods, if not invoked with any arguments, will return the array which holds all the current callbacks assigned to that 'callback site'

To clear the before_save ones, you can simply do

before_save.clear

and it seems to work

Orion Edwards
A: 

Again poking around in the source, it seems that validations can be run either on every save, or updates/creates only. This maps to

:validate => all saves
:validate_on_create => creations only
:validate_on_update => updates only

To clear them, you can use write_inheritable_attribute, like this:

write_inheritable_attribute :validate, nil
Orion Edwards
+4  A: 

I like to use the following pattern:

class Parent < ActiveRecord::Base
  validate_uniqueness_of :column_name, :if => :validate_uniqueness_of_column_name?
  def validate_uniqueness_of_column_name?
    true
  end
end

class Child < Parent
  def validate_uniqueness_of_column_name?
    false
  end
end

It would be nice if rails provided a skip_validation method to get around this, but this pattern works and handles complex interactions well.

This one seems to be the most correct actually.
rabble