Left column
You could use this column as some sort of
news box, link list, or a second navigation. It would also
be quite feasable to move this to the right and have the
navigation here.
Custom designs
Schools out, and I don't have too much on the go right now,
so if you want a custom design made, give me a shout, and I'll
make you a template for a very fair price.
About the Author
My name is Kevin Cannon. I live just outside of Vancouver,
Canada. I've been dabbling in web design for a while, and this is
my fourth template submitted to OSWD. Most of my work, no wait ...
all of my work has been done for free so far. Maybe I will do
web design for a living, but probably not.
What is a 'Productized Rails Application'?
At MyTechSupport, we often have clients who pay a few thousand dollars for
a web site, but in order to make a profit, we need to re-sell our work to
other companies with similar business needs. For example, we are currently
working on an adoption site (Jul 2005). Adoption sites, in general, have
some generic needs (e.g. a "Birth Mother" login and a "Waiting Family"
login), but our client has some particular needs as well.
Using the following code, you can create a single generic application which
uses a separate database for each client. In addition, you will have a
hierarchical application structure wherein add-ons and tweaks for specific
customers are possible without affecting the core "generic" site code base
(neither will you have to copy that code base for each application). In
this way, you can maintain a core application code base that every client
uses, while still providing flexibility for paid add-ons or site-specific
needs.
= Installation
To install the rails_product generator, simply run:
$ gem install rails_product
(This assumes you have the prerequisites to Rails already installed, e.g.
Ruby 1.8.2 2004-12-25 and the 'gem' shell command from rubyforge.org).
Next, you'll want to make sure you have the site generator as well:
$ gem install site_generator
The site generator will create a hollow directory structure for each site
that you add to your base application.
So, now that you've got the gems installed, here's how you'd create your
very first Rails product:
$ cd ~/Projects
$ rails_product shopping_cart
create
create app/apis
create sites
create Rakefile
create README
create CHANGELOG
create app/controllers/application.rb
create app/helpers/application_helper.rb
create test/test_helper.rb
create config/database.yml
create config/routes.rb
create public/.htaccess
create sites/Rakefile
$ cd shopping_cart
$ ./script/generate site my_first_cart_client
create sites/my_first_cart_client/app/controllers
create sites/my_first_cart_client/app/helpers
create sites/my_first_cart_client/app/models
create sites/my_first_cart_client/app/views/layouts
create sites/my_first_cart_client/db/migrate
create sites/my_first_cart_client/log
create sites/my_first_cart_client/public
create sites/my_first_cart_client/config
create sites/my_first_cart_client/test/fixtures
create sites/my_first_cart_client/test/functional
create sites/my_first_cart_client/test/unit
create sites/my_first_cart_client/public/.htaccess
create sites/my_first_cart_client/public/dispatch.fcgi
create sites/my_first_cart_client/config/routes.rb
$ ./script/server -s my_first_cart_client
=> Productized Rails application started on http://0.0.0.0:3000
...
At this point, assuming your application is going to be using a
database, you'll want to go make your first site's database. Depending on
how you do things, you'll want to make one, two, or possibly all three of
these databases:
my_first_cart_client_dev
my_first_cart_client_test
my_first_cart_client
The last database in that list is the production database.
= How Does The Directory Structure Differ From a Regular Rails Application?
The directory structure of the Generic application is just like a normal
Rails application, with one additional directory: the "sites" directory. So
it looks something like this:
RAILS_ROOT/
app/
controllers/
helpers/
models/
views/
public/
sites/
best_ever_adoptions_co_inc/ # <-- Site #1
app/
controllers/
helpers/
models/
views/
config/
db/
migrate/
public/
test/
fixtures/
functional/
unit/
yet_another_adoption_co/ # <-- Site #2
app/
controllers/
helpers/
models/
views/
(etc.)
Note that although the directory structure of each individual site is
almost identical to a regular Rails application, you need not have ANY
files in these directories. In fact, you can omit any directory (except
the SITE_ROOT, e.g. sites/best_ever_adoptions_co_inc/) if it does not
contain files. So how does it work?
Well, if you put a file called, for example, welcome_controller.rb in
RAILS_ROOT/app/controllers, then all of your sites will access that
controller as normal UNLESS you put a file with the same name in the
site-specific controllers folder. In that case, the RAILS_ROOT
welcome_controller.rb will be loaded, and then the WelcomeController class
will be reopened (yay for Ruby!) by the site-specific welcome_controller.rb
(say, for example, in
RAILS_ROOT/sites/yet_another_adoption_co/app/controllers/) and modified as
needed. For example, you could override the "index" method to do a
redirect, or you could add a before_filter to make the controller require a
login.
Views, layouts and partials act similarly--however, they simply override
their generic counterparts. For example, if you have an index.rhtml and a
_title.rhtml in RAILS_ROOT/app/views/welcome/ and supposing this
index.rhtml has a <%= render :partial => "title" %> in its code, then the
_title partial will be rendered in place. Now, however, let's say that we
put a _title.rhtml file in
RAILS_ROOT/sites/yet_another_adoption_co/app/views/welcome/. In that case,
our generic index.rhtml will load the site-specific _title partial in
place. Hierarchical customizations in a jiffy.
= Implementation Details
If you would like to understand how all of the pieces work together to
accomplish this feat, read on.
Here is what the rails_product generator will do:
1. Create the RAILS_ROOT directory structure as usual, with the addition
of a /sites folder.
2. Create a productize.rb file in your application's lib/ folder (open it
and read the comments to see what it does exactly. This is where the core
magic happens since we can re-open the Rails classes as necessary to allow
for our productization approach.)
3. Create a slightly modified environment.rb file in your config/ folder.
The following three lines are different from the regular environment.rb:
a. SITE = ENV['SITE'] || ENV['site']
Sets a constant for the rest of the application so it can know where
to find your site's stuff.
b. require 'productize'
Modifies the core Rails classes as necessary to load both the base
application's code and the site-specific code.
c. File.join(SITE_ROOT, 'app', 'controllers'),
Lets the Dependencies::LoadingModules class know where to find site-
specific controllers if the base controller doesn't exist.
4. Create a modified database.yml file that will dynamically load the
correct database when the server starts up.
5. Create an 'apache' directory in your config/ folder with a sample Apache
VirtualHost configuration file. This sample file will show you what you'll
need to do to get Apache to behave like WEBrick below (shares resources).
6. Create a modified script/server file that will let your WEBrick server
share the resources in your base application's public folder (e.g. images,
javascripts etc.) without having to copy them to each site's individual
public folder (Hurray for the DRY principle!) (DRY=Don't Repeat Yourself).
Simplicity
= What is a 'Productized Rails Application' ?
At MyTechSupport, we often have clients who pay a few thousand dollars for
a web site, but in order to make a profit, we need to re-sell our work to
other companies with similar business needs. For example, we are currently
working on an adoption site (Jul 2005). Adoption sites, in general, have
some generic needs (e.g. a "Birth Mother" login and a "Waiting Family"
login), but our client has some particular needs as well.
Using the following code, you can create a single generic application which
uses a separate database for each client. In addition, you will have a
hierarchical application structure wherein add-ons and tweaks for specific
customers are possible without affecting the core "generic" site code base
(neither will you have to copy that code base for each application). In
this way, you can maintain a core application code base that every client
uses, while still providing flexibility for paid add-ons or site-specific
needs.
= Installation
To install the rails_product generator, simply run:
$ gem install rails_product
(This assumes you have the prerequisites to Rails already installed, e.g.
Ruby 1.8.2 2004-12-25 and the 'gem' shell command from rubyforge.org).
Next, you'll want to make sure you have the site generator as well:
$ gem install site_generator
The site generator will create a hollow directory structure for each site
that you add to your base application.
So, now that you've got the gems installed, here's how you'd create your
very first Rails product:
$ cd ~/Projects
$ rails_product shopping_cart
create
create app/apis
create sites
create Rakefile
create README
create CHANGELOG
create app/controllers/application.rb
create app/helpers/application_helper.rb
create test/test_helper.rb
create config/database.yml
create config/routes.rb
create public/.htaccess
create sites/Rakefile
$ cd shopping_cart
$ ./script/generate site my_first_cart_client
create sites/my_first_cart_client/app/controllers
create sites/my_first_cart_client/app/helpers
create sites/my_first_cart_client/app/models
create sites/my_first_cart_client/app/views/layouts
create sites/my_first_cart_client/db/migrate
create sites/my_first_cart_client/log
create sites/my_first_cart_client/public
create sites/my_first_cart_client/config
create sites/my_first_cart_client/test/fixtures
create sites/my_first_cart_client/test/functional
create sites/my_first_cart_client/test/unit
create sites/my_first_cart_client/public/.htaccess
create sites/my_first_cart_client/public/dispatch.fcgi
create sites/my_first_cart_client/config/routes.rb
$ ./script/server -s my_first_cart_client
=> Productized Rails application started on http://0.0.0.0:3000
...
At this point, assuming your application is going to be using a
database, you'll want to go make your first site's database. Depending on
how you do things, you'll want to make one, two, or possibly all three of
these databases:
my_first_cart_client_dev
my_first_cart_client_test
my_first_cart_client
The last database in that list is the production database.
= How Does The Directory Structure Differ From a Regular Rails Application?
The directory structure of the Generic application is just like a normal
Rails application, with one additional directory: the "sites" directory. So
it looks something like this:
RAILS_ROOT/
app/
controllers/
helpers/
models/
views/
public/
sites/
best_ever_adoptions_co_inc/ # <-- Site #1
app/
controllers/
helpers/
models/
views/
config/
db/
migrate/
public/
test/
fixtures/
functional/
unit/
yet_another_adoption_co/ # <-- Site #2
app/
controllers/
helpers/
models/
views/
(etc.)
Note that although the directory structure of each individual site is
almost identical to a regular Rails application, you need not have ANY
files in these directories. In fact, you can omit any directory (except
the SITE_ROOT, e.g. sites/best_ever_adoptions_co_inc/) if it does not
contain files. So how does it work?
Well, if you put a file called, for example, welcome_controller.rb in
RAILS_ROOT/app/controllers, then all of your sites will access that
controller as normal UNLESS you put a file with the same name in the
site-specific controllers folder. In that case, the RAILS_ROOT
welcome_controller.rb will be loaded, and then the WelcomeController class
will be reopened (yay for Ruby!) by the site-specific welcome_controller.rb
(say, for example, in
RAILS_ROOT/sites/yet_another_adoption_co/app/controllers/) and modified as
needed. For example, you could override the "index" method to do a
redirect, or you could add a before_filter to make the controller require a
login.
Views, layouts and partials act similarly--however, they simply override
their generic counterparts. For example, if you have an index.rhtml and a
_title.rhtml in RAILS_ROOT/app/views/welcome/ and supposing this
index.rhtml has a <%= render :partial => "title" %> in its code, then the
_title partial will be rendered in place. Now, however, let's say that we
put a _title.rhtml file in
RAILS_ROOT/sites/yet_another_adoption_co/app/views/welcome/. In that case,
our generic index.rhtml will load the site-specific _title partial in
place. Hierarchical customizations in a jiffy.
= Implementation Details
If you would like to understand how all of the pieces work together to
accomplish this feat, read on.
Here is what the rails_product generator will do:
1. Create the RAILS_ROOT directory structure as usual, with the addition
of a /sites folder.
2. Create a productize.rb file in your application's lib/ folder (open it
and read the comments to see what it does exactly. This is where the core
magic happens since we can re-open the Rails classes as necessary to allow
for our productization approach.)
3. Create a slightly modified environment.rb file in your config/ folder.
The following three lines are different from the regular environment.rb:
a. SITE = ENV['SITE'] || ENV['site']
Sets a constant for the rest of the application so it can know where
to find your site's stuff.
b. require 'productize'
Modifies the core Rails classes as necessary to load both the base
application's code and the site-specific code.
c. File.join(SITE_ROOT, 'app', 'controllers'),
Lets the Dependencies::LoadingModules class know where to find site-
specific controllers if the base controller doesn't exist.
4. Create a modified database.yml file that will dynamically load the
correct database when the server starts up.
5. Create an 'apache' directory in your config/ folder with a sample Apache
VirtualHost configuration file. This sample file will show you what you'll
need to do to get Apache to behave like WEBrick below (shares resources).
6. Create a modified script/server file that will let your WEBrick server
share the resources in your base application's public folder (e.g. images,
javascripts etc.) without having to copy them to each site's individual
public folder (Hurray for the DRY principle!) (DRY=Don't Repeat Yourself).