#62
Jul 25
Hacking ActiveRecord
Have you ever wanted to temporarily disable all validations? Well, ActiveRecord doesn't support this, but that doesn't mean we can't add it. This episode will show you how to open up an existing class and change its behavior.
Resources
# test_helper.rb class Test::Unit::TestCase self.use_transactional_fixtures = true self.use_instantiated_fixtures = false def disable_validation ActiveRecord::Base.disable_validation! yield ActiveRecord::Base.enable_validation! end end module ValidationDisabler def self.included(base) base.class_eval do extend ClassMethods alias_method_chain :valid?, :disable_check end end def valid_with_disable_check? if self.class.validation_disabled? true else valid_without_disable_check? end end module ClassMethods def disable_validation! @@disable_validation = true end def enable_validation! @@disable_validation = false end def validation_disabled? @@disable_validation ||= false end end end class ActiveRecord::Base include ValidationDisabler end
Note there is a slight problem with how I set the default value for the class variable in the screencast. The code posted here should be correct.
Ideally I would use something like class_inheritable_accessor instead of a class variable, but I was unable to get this to work. Please comment if you have a suggestion.




This is a jewel. I used most of these techniques before without fully understanding what's that self.included(base) thing is about. Now I know! And the example is well choosen. In a real app often it doesn't make sense to cramp the different aspects of a technique into one place. Here it seems quite reasonable.
Thank you!
let me see
Hi Ryan,
great job, congratulations!!!
Please, what program do you use for editing the video and export to .mov?
Great screencast, Ryan. You've put up a good summary of how to easily change the behavior of any class. Of course it does not only work with ActiveRecord, but with virtually every class.
To disable validations, so far I was using save_without_validation! instead of save! (AR itself uses alias_method_chain to add validations), however your plugin might come in handy to disable validations in a larger context.
Btw, you're publishing new screencasts faster than I can watch them :)
Nice...
@chivi, I'm using Final Cut Pro to edit them and Quicktime Pro to convert them.
@Zargony, right. You can also use "save(false)" to bypass validation. I often find myself using "create" more than "save" so it's convenient to have this plugin.
Great screencast on extending AR!
My favorite way to modify this sort of behavior is using mocha to do a:
Product.any_instance.stubs(:valid?).returns(true)
I think flexmock has a similar new_instances method. Unfortunately rspec doesn't have this functionality yet which is why I use mocha.
I have watched all your episodes so far and your hard work is greatly appreciated.
You have helped me greatly to jumpstart my web programming skills.
Your screencasts are simply the best I have found and their high quality makes every episode worth watching...
Keep up the great work!
Once again you have saved me hours of reading and days of trial and error! Bless you for your charity :-)
just pass false to model save, this saves without validations...like this
# will save person even though zip fails validation
person = Person.new
person.zip = "badzip"
person.save false
@youtubesearcher, true. But this doesn't work for the convenient "create" and other methods related to saving models.
True enough, but it also does not require hacking thru activerecord and exposing yourself to breakage when a new rails release or patch comes out...but hey...both work and it's just a matter of personal preference
thanks for these screencasts.
i think it will be more ruby idiomatic if you did
def valid_with_disable_check?
return self.class.validation_disabled? ||
valid_without_disable_check?
end
rather than
def valid_with_disable_check?
if self.class.validation_disabled?
true
else
valid_without_disable_check?
end
end
check http://rubygarden.org/Ruby/page/show/RubyIdioms
regards and keep these gems
Hi ryan,
It was a good walk through... in a way also revising my OOPS concepts.. hehe
@youtubesearcher: "hacking" through activerecord was the point of the exercise. Lots of these vids aren't necessarily about the most efficient or best way to get X done, but teaching techniques and ways of doing things that lots of us find useful.
@ryan: excellent vid. I think lots of people know what they can do with self.included, sort of, but maybe not exactly why. Thanks for all your work.
Great job! Thanks!
Instead of
base.class_eval do
extend ClassMethods
end
you can do just
base.extend ClassMethods
. Since you're calling another method on the same object – alias_method_chain – I suppose there's a case for using class_eval, but viewers might be interested to know there is a slightly simpler way.
Awesome screentcast. I was looking for a way to bypass validation with my functional testing and this provided an extensible solution. Great job and thank you for all your work.
I'm shocked, i'll have to see it another 2 or more times before understand it all. But it's really nice, and i'll use this approach for some good refactoring in the code :)
Thanks for another great screencasts. All of them have been very helpful and timesaving to me and my friends studying rails!