Over my time of using Rails I've struggled with the placement of code that does not explicitly belong to a controller, model or view. My Java background probably had a lot to do with my selection of the lib dir for all 'extra' code when I first started.
Then I learned about plugins and loved the auto require feature. No more requires in my environment.rb. Sweet, but I didn't feel everything qualified as a plugin, or at least to my definition of a plugin. So now I have some code in the plugin directory and some code in the lib dir without any rule on where to look for a particular type of code. Things are starting to get messy.
I wasn't stopping there. I decided to use helpers for their intent to house "view only" code. This cleaned up my lib directory some but now there are three places to look. You would think that would be enough. Oh no, there's more!
Rails 2.0 introduced config/initializers and I thought this was great, the answer to my dilemma of lib vs plugin. Code in the initializers dir is loaded automatically like the plugin and it wasn't "way out there" in vendor/plugins so it felt more like a part of the application. Initializers for everything!
...
Those of you who have been coding for a while realize that this is a bad idea. Nothing is for everything. So before I went on my mindless bulk move, I decided I needed to think about this some. This is what I have decided.
View code goes in the helper. That was easy.
Plugins should be reserved for generic functionality such as attachment_fu. For every project you write that needs file uploads you can use this same plugin. You don't have to alter the code on a per project basis. It's good to go. So, if you have multiple applications and you find yourself copying code over and over without modifications, it should probably be a plugin.
In one sense, I consider initializers to be plugins that may need some degree of customization. Project constants are something you use all the time, but they need to be specific for the project. Even though you may reuse a lot of the same constants, odds are some will be specific to the project. Don't separate out the ones that never change to a plugin. This leaves you with two places to look and will cause you headaches.
Another use for initializers is code that is used throughout your application, but it's not generic enough to be a plugin. A module that maintains your session is a perfect example.
This leaves the lib directory. This should be reserved for specialized functionality, something only a couple of controllers or models may use and would be "required" only where necessary. Specialized math or string methods come to mind.
Another, more common use of the lib directory would be to house modules that eliminate repetitive code. For example, say I have multiple models using the same find method like find_recent_posts_by_author. This could be applied to books, pages, comments, etc... I don't want to rewrite this find_recent_posts_by_author method in each of those models. So, I write it once in a module and include it in only the models that need that functionality.
Well, that's all for now, I'm still refining things. If you disagree or have another rule, I'd like to hear it.
thanks.
Thursday, March 20, 2008
Wednesday, March 19, 2008
Stage generator update
I've updated stage to remove the automatic inclusion of unit tests. This is one step closer to adding in the choice between unit tests and rspec.
As always (like it's been out for a long time), you can grab it here:
For more info please see the original post.
As always (like it's been out for a long time), you can grab it here:
$ ./script/plugin install http://stonean.googlecode.com/svn/stage/trunk
For more info please see the original post.
Labels:
RubyOnRails,
Stage
Tuesday, March 18, 2008
MysqlUtils update
I added a quick little feature to the mysql_utils plugin:
t.userstamps will add created_by (integer) and updated_by (integer) fields to your table.
create_table :messages do |t|
#some meaningful fields
t.userstamps
t.timestamps
end
t.userstamps will add created_by (integer) and updated_by (integer) fields to your table.
Labels:
MysqlUtils,
RubyOnRails
Fusion
This is completely vaporware at the moment, but I wanted to throw this out there to see if anyone has any constructive comments.
Please note this is highly theoretical so don't slam me too hard for missing functionality. :)
I have plans for a couple of applications that will share some of the same functionality. One of the applications will be open source while others will be service offerings incorporating some of the features of the open source project.
What I want to do is to have the commercial projects include the parts of the open source project and get the relevant updates. Essentially I want them fused. I don't want to add specialized directories for this and I don't want everything pushed into the plugin. I want the open source application to be a part of the commercial application.
So enter the idea of Fusion. Fusion will be a rake task that will feed of off a yml file detailing the application you want fused into your own.
Here's a sample yml file:
The rake task will export the code into a temp dir and then merge them into your directory. It will need to warn for collisions on resources so that means some sort of inventory mechanism, but I don't think that's a big deal.
The views would feed off of the controller names (Rails convention stuff) and fuse the directory contents.
Some rake tasks could look like:
Well, that's the basic idea. I'm still fleshing out the details.
Please note this is highly theoretical so don't slam me too hard for missing functionality. :)
I have plans for a couple of applications that will share some of the same functionality. One of the applications will be open source while others will be service offerings incorporating some of the features of the open source project.
What I want to do is to have the commercial projects include the parts of the open source project and get the relevant updates. Essentially I want them fused. I don't want to add specialized directories for this and I don't want everything pushed into the plugin. I want the open source application to be a part of the commercial application.
So enter the idea of Fusion. Fusion will be a rake task that will feed of off a yml file detailing the application you want fused into your own.
Here's a sample yml file:
address_book:
repo: https://stonean.googlecode.com/svn/address_book/trunk
models: address.rb
controllers: address_controller.rb
migrations: _create_addresses.rb, _add_county_to_addresses.rb
books_repo:
repo: https://stonean.googlecode.com/svn/book_repo/trunk
models: book.rb, author.rb
controllers: books_controller.rb, authors_controller.rb
migrations: _create_books.rb, _create_authors.rb
#Grab all models,views,controllers,migrations
shopping_cart:
The rake task will export the code into a temp dir and then merge them into your directory. It will need to warn for collisions on resources so that means some sort of inventory mechanism, but I don't think that's a big deal.
The views would feed off of the controller names (Rails convention stuff) and fuse the directory contents.
Some rake tasks could look like:
#Sync with all applications defined in the fusion.yml
rake fuse:all
#Show what files would be updated
rake fuse:all --show
#Sync with specific applications
rake fuse:application addresses
Well, that's the basic idea. I'm still fleshing out the details.
Labels:
Fusion,
RubyOnRails
Subscribe to:
Posts (Atom)
