How can I disable a validation and callbacks in a rails STI derived model?
Solution 1
As a variation of the answer by @Jacob Rothstein, you can create a method in parent:
class Parent < ActiveRecord::Base
validate_uniqueness_of :column_name, :unless => :child?
def child?
is_a? Child
end
end
class Child < Parent
end
The benefit of this approach is you not need to create multiple methods for each column name you need to disable validation for in Child class.
Solution 2
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
Solution 3
A cleaner way is this one:
class Parent < ActiveRecord::Base
validate :column_name, uniqueness: true, if: 'self.class == Parent'
end
class Child < Parent
end
Or you can use it also in this way:
class Parent < ActiveRecord::Base
validate :column_name, uniqueness: true, if: :check_base
private
def check_base
self.class == Parent
end
end
class Child < Parent
end
So, uniqueness validation is done if the instance class of model is Parent
.
- Instance class of
Child
isChild
and differs fromParent
. - Instance class of
Parent
isParent
and is the same asParent
.
Solution 4
Since rails 3.0 you can also access the validators
class method to manipulate get a list of all validations. However, you can not manipulate the set of validations via this Array.
At least as of rails 5.0 you however seem to be able to manipulate the _validators
(undocumented) method.
Using this method you can modify the validations in the subclass like e.g.:
class Child < Parent
# add additional conditions if necessary
_validators.reject! { |attribute, _| attribute == :parent_id }
end
While this uses an undocumented method, is has the benefit of not requiring the superclass to know anything about the child's implementation.
Mitkins
I do .NET, C++, Ruby, Automated Testing, Running and Snowboarding@borland
Updated on June 22, 2022Comments
-
Mitkins almost 2 years
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 fromBaseModel
, including thevalidates_presence_of :parent_id
. I would like to turn the validation off forDerivedModel
, and prevent the callback methods from firing, preferably without modifying or otherwise breakingBaseModel
What's the easiest and most robust way to do this?
-
Leszek Andrukanis over 10 yearsAwareness of existing Child class in the Parent isn't the best approach. I'm trying to cope with it in other way.
-
VoodooChild92 over 8 yearsHey.. This is a great way you suggested. I am using a class from a gem, so I can't change the Parent class and the function "check_base". Can you suggest me a way where I add some sort of validation skip in the child class.
-
Sidhannowe over 4 yearsShorter:
validate_uniqueness_of :column_name, :unless => "is_a? Child"