Archives for Feb 2006
active record calculations
If you happen to be on edge rails and using my ActiveRecord Calculations plugin, you can safely remove it. It’s been accepted for Rails 1.1.
unitialized constant "Technoweenie"
One of the nice things about Rails is how it handles the loading and reloading of your classes. Support for convenient loading has always been around, but in Edge Rails you’ll find there is even less work needed, especially if you do much plugin and framework development. Check this out.
Auto Loading Classes
The first thing that you must know is that Rails does not automatically load your application. It initializes the framework, runs your plugin init.rb files, and includes your app/ and lib/ directories in the LOAD PATH. But, it doesn’t do anything with application classes until you start accessing them. Try accessing your Article model, and it immediately attempts to load article.rb. Access MyModule::Article, and it looks for my_module/article.rb. This behavior has been around for awhile, but the implementation is much smarter.
Reloadable
The big change deals with the reloading of classes in development mode. Before, the dispatcher would clear specific subclasses of some Rails core classes. This meant that any custom classes were left out in the cold. However, this functionality has been extracted out so any class can utilize it.
# foo.rb
class Foo
include Reloadable
end
Now, any of those custom classes will be reloaded along with the rest. If you have some core library code that you don’t want reloaded, however, you can use this:
# foo/base.rb
# This is put in a module MyModule to mimic something like ActiveRecord::Base
# the module is not required for this however
module MyModule
class Base
include Reloadable::Subclasses
end
end
# this class will be reloaded on every request
class Foo < MyModule::Base
end
This keeps your MyModule::Base safe from the clutches of the reloader, but not any subclasses. This is how the rails base classes stay in memory, while allowing your models/controllers/etc to reload.
Rules
If you want to take advantage of Rails’ auto class loading capabilities, there are a few guidelines you need to follow. Of course, if you don’t follow these rules, you’ll be stuck using require statements…
The first thing to keep in mind is that classes should be organized one to a file. They should have reasonable class names that map to guessable filenames.
- Foo => foo.rb
- MyModule::Foo => ‘my_module/foo
Use the string inflectors to check the names if something isn’t loading correctly. Don’t use uppercase class names though, because they don’t work both ways.
> 'MyModule::Foo'.underscore
=> "my_module/foo"
> "my_module/foo".classify
=> "MyModule::Foo"
> "SSLClass".underscore
=> 'ssl_class'
> "ssl_class".classify
=> "SslClass" # doh!
One common problem is adding multiple classes with STI. For instance, it’s temping to just throw a quick Admin class at the bottom of a User class definition. That’s all fine and dandy until the objects are wiped and reloaded. If the next controller action accesses Admin before User, you’re going to have problems.
Be careful about file name clashes as well. If your Article class needs to load, but your app has article.rb in various spots, only one of them will be loaded. Naturally, you’ll want to put things in proper module namespaces. This is especially important for plugins. Be sure to put your libraries files in some unique module namespace to be safe.
Another source of clashing is modules matching currently existing classes. If Rails attempts to autoload “MyModule::Foo,” it expects MyModule to be a an actual module. If it loads my_module.rb and finds a Class, it will cause issues. However, you are allowed to load modules like this:
./my_module.rb # loaded on first access of MyModule
./my_module/foo # uses the same MyModule module, and adds Foo class
./my_module/foo/bar # this will raise an error since Foo is a class.
Getting around Reloadable
There are times when you don’t want your models, controllers, etc to reload. So, what’s a guy to do?
class NoReload < ActiveRecord::Base
def self.reloadable?
false
end
end
When the dispatcher removes the classes after a request, classes that answer false to klass.reloadable? are skipped.
quick like ninja
mongrel
I’ve replaced webrick with mongrel as my rails web development server. Lighttpd and/or fcgi didn’t install correctly on my powerbook, so I’ve been using webrick for awhile. mongrel, however, is quick and doesn’t require any config files. Windows users: don’t despair! Zed tells me that a windows mongrel service will be coming out too.
rails recipes
Chad Fowler’s latest book, Rails Recipes kicks ass. His last one, My Job Went to India was one of the catalysts that got me thinking about moving to freelancing… The other was 1000 Steps to World Domination.
more mephisto changes
Sorry guys, I went and broke things again by renaming Mephisto categories to sections. I think that name more accurately describes what they are. This is just another warning that Mephisto is still not ready for actual use.
Javascript Quiz: what's wrong with this code?
['a', 'b', 'c'].each(function(id) {
alert(id)
})
['d', 'e', 'f'].each(function(id) {
alert(id)
})
Assume that prototype is being used, of course.
ActiveRecord Callbacks and STI
One of the things I’ve done with Mephisto is started using STI more. For instance, I have a basic Content model, with an Article and Comment deriving from it. But, I noticed that none of my validations or callbacks were not making it from my base model.
How are Callbacks and Validations saved?
Checking lib/active_record/callbacks.rb shows that the class methods write an inheritable array. You can then check the current callbacks with this:
>> Article.new.send :callbacks_for, :before_save
=> [] # this is where you'd see an array of symbols, procs, etc
Validations in lib/active_record/validations.rb are saved with an inheritable array also. Validations can be checked with:
>> Article.read_inheritable_attribute(:validate)
=> [] # you'll see an array of procs for this validation method
So, I know my callbacks and validations are not working, but why? After much digging and debugging, I finally pinpointed two causes. They are definitely two rare edge cases, but the investigation led me to a deeper understanding of Rails.
Class.inherited()
The first has to deal with using the inherited(). It’s a method that is called whenever a class is inherited from. I was using this to add a set of callbacks to any class that inherited from my base Content class:
class Content < ActiveRecord::Base
def self.inherited(sub)
sub.before_save :do_something
end
end
The problem is this is exactly how inherited class attributes are passed on. By defining inherited on my class, I was overriding the method that transfers my callbacks and validations. This is not a big deal. Instead of trying to be clever, I used a mixin to copy the functionality.
More Issues
After fixing that, I started seeing some intermittent issues with disappearing callbacks. This time I overwrote self.inherited() to see when it was being called, and what inherited attributes it was passing on. The problem, I noticed, was that it passes them at the creation of the subclass. What if you have code like this?
class Article < ActiveRecord::Base
has_many :comments
validates_uniqueness_of :title
end
While loading the Article class, it will load the Comment class while creating the has_many association. In my case, Comment was a subclass of Article and would get loaded before my validations and callbacks. From now on, I’m going to start putting my association calls below my callbacks and validations. If you’re seeing weird issues with callbacks and validations too, I’d suggest you do the same.
it's new! it's green!
I recently got contacted by Justin Palmer about mephisto. He seemed to like the approach and noticed my complete lack of design skills. We discussed some future possibilities of the app and spent some time during the weekend working on it. At this point, he’s integrated most of his new admin layout. I spent the time renaming models and completely reworking the templates.
It’s still not ready for a public release, but I finally upgraded this blog with it.
what is 'mephisto' anyway?
Lately, there has actually been some interest in Mephisto, my little blogging app. It started out as my own personal escape from other blogging apps that just didn’t do it for me. It’s still not ready and polished for heavy use yet. But since it’s out there being used already, I figured I’d start talking about it some.
If you happen to check it out from subversion, be sure to run the task rake install_mephisto to get going. This sets up the database schema and the default liquid templates. Now one area that is severely lacking is the documentation. The current default template is very plain, and won’t give you an idea of what you can accomplish with the Mephisto liquid tags. If you’re adventurous, you can pull up an old dump of this weblog’s templates. Oh by the way, this requires edge rails. I have a rails weenie tip on setting that up.
One question I get asked a lot though, is where does the name come from? Mephisto the name is actually a reference to a Marvel Comics Villain. I was fishing for names and was fond of “manifest.” I didn’t get many warm reactions to the name, so I dug into my geek roots and pulled out ‘Mephisto.’ I can’t say I’m even a fan of the character, but the name stuck.
Update: atmos added a more detailed walkthrough on setting Mephisto up with Switchtower
non-essential feature of the week
This week’s non-essential feature is of course, the Friends’ Pages section on Backpack.
Register for RailsConf
The registration for RailsConf has just opened. I hope to see you all there!
