In the midst of all these CRUD discussions and app organization tips, I’d like to submit a slightly less controversial idea: organize your models without resorting to namespacing.
How? Here’s a typical app/models directory.
Yikes. Way too many models. But let’s say we need them all and don’t really want to deal with namespacing. The first thing to do, as with any type of organizing, is separate our large group into smaller logical groupings. In this case we have three: database models, which map directly to a database table, cache models, which do not map directly to a database table and live in memcached, and tableless models, which we use to take advantage of ActiveRecord’s validations without using database table.
We create three subdirectories under model to represent our smaller groups: database, cache, and tableless. Like so.
That’s a lot better. It’s immediately clear which models do what. Now, how do we get Rails to recognize the models in these subdirectories without having it assume they fall under the namespace of the subdirectory itself?
We don’t.
Rails will automatically find these models without any problem. There will be no difference in your code, just less mental overhead when jumping through your directory tree.
You can also use this trick to better organize your controllers, helpers, plugins, or libraries. Thanks, Rails.
Update: Getting this to work in Rails 1.2+ is simple. Simply add the subdirectories of models to your config.load_paths array in your Rails::Initializer.run block. Like this:
Rails::Initializer.run do |config| config.frameworks -= [ :action_web_service ] config.load_paths += %W[ #{RAILS_ROOT}/app/models/api #{RAILS_ROOT}/app/models/cache #{RAILS_ROOT}/app/models/database #{RAILS_ROOT}/app/models/tableless ] end
A further thing could be organising your models with modules, but Rails is a bit sketchy on how to do this (in development mode, the require_or_load uses a hash based lookup so if you have item/purchase.rb and credit/purchase.rb you’re going to have problems).
That’s a pretty nice solution what you’ve suggested.
I just tried your solution with migrations, and unfortunately it seems rails doesn’t find migration files in subdirectories of db/migrate. Any ideas?
Martin: The migrations directory is a bit sketchy because Rails depends on the numerical sort order of the files within when running migrations. To split it up into subdirectories, you’d probably have to change the Rails code a bit.
It seems to me that this doesn’t work at all. Maybe this is just for Rails 1.2+ but I have a single-table-inheritance set up and so I have a table with all sorts of widgets. So I have a widget model. Then I have models for red widgets and blue widgets. My models directory looks like:
- user.rb - widget.rb + widgets – red_widget.rb – blue_widget.rb
It doesn’t work. I get:
“The single-table inheritance mechanism failed to locate the subclass: ‘RedWidget’.”
until I pull red_widget.rb out of the widgets folder. Then it works like a charm. What gives? I have so many models that this level of organization is a must. Please advise. Thanks!
I guess my clever directory structure formatting didn’t get along with the comment formatting. Hopefully, you get the idea. I have most of my models in the models directory with some subdirectories to hold single-table-inheritance subclasses.
That’s really great tip to organize your models.
You could also use a glob in the load_paths line. Then you don’t have to remember to update the directories all the time:
config.load_paths += Dir[”#{RAILS_ROOT}/app/models//“]
Aww, textile… you make me cry a little inside every time you do stuff like that.
That’s
This all worked fine until I wanted to convert my app to a plugin (with Rails Engines). I found this helpful for getting the load paths right:
http://weblog.techno-weenie.net/2007/1/24/understanding-the-rails-initialization-process
I have been using this trick but am getting some weird issues. I have a dir called Player and then have several models inside it (lets say Playback and Video for example). I am getting errors where it complains that Player/Video should define Player::Video instead of Video. If I change it to define Player::Video, I get a different error that it should define Video instead of Player::Video. Clearly I have angered Rails.
Any thoughts? I have a ton of models in subfolders, and there are only a couple that misbehave like this.
I am using Rails 1.2.3 for reference.
Chime in.