#62 Hacking ActiveRecord
Jul 25, 2007 | 11 minutes | Active Record
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.
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!
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 :)
@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.
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!
@ryan
what i keep trying to wrap my head around is how does rails/ruby know where all these "hacks" are to compile them into a class. is activerecord a singleton in memory? i just don't get it.
Why can't we just...
class ActiveRecord::Base
extend ClassMethods
end
to add those module methods as class methods?
I'm using your plugin to disable validation on the backend side of our application. it works fine. but with validation enabled on the frontend side i get SystemStackError: stack level too deep Error.
there are 4 models involved in the transaction using all of belongs_to, has_many :through as well as :polymorphic
Hi, Ryan
you mention at the top that you tried to use class_inheritable_accessor, but it did not work.
An accessor is indeed a lot better rather than a class variable (for several reasons); but here we can just use cattr_accessor (as we don't need to deal with different values in the Inheritance tree).
It worked, simplifying things significantly (code is cut in half): http://pastie.org/352681
I started watching all your screencasts (from the first one): a terrific way to see Rails from all angles!
The juries is not giving point by the taste of the food, but this a competition of designing food. So they will look for a good looking one.
Very interesting once again... though I read about
alias_method_chain
that in rails 3> it has been replaced by a clever use of method overriding in modules and the super keyword.
on stackoverflow
Thanks a lot!
any idea how to create a separate class variable to each model inheriting from ActiveRecord::Base?
@@disable_validation will be the same object to all classes that inherit from ActiveRecord::Base, and I don't want that. =[ I need to create a specific counter to each Rails Model.
any tip?
found it: