I am building a series of Rails applications for different users and use cases, but they all hang off the same database schema. Using canonical Rails, that means a single, massive rails app with a bunch of controllers, a heap of views and a complex security model.
I prefer small, focussed apps, so I decided to share the model instead. Here’s how it works.
Sharing the model
Lets call the the first rails project Master. Generate it as usual and create a few models and migrations to set up the database. In my case, the Master rails application is used to do nothing more than import, export and allow users to view the data in the model’s database tables.
rails new Master --database postgresql cd Master rails generate model model1 ... ... rake db:create rake db:migrate
Lets now create a reporting app, called Reporting that will use the same model as Master.
cd .. rails new Reporting --database postgresql cd Reporting
Do not create any models or migrations in this project, you do them all in Master.
To copy the models, create a new
rake task in a new file in Reporting called
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
source_path to point to the root of the Master project and the
dest_path to point to the root of the Reporting project. The run it:
The script copies the
database.yml files from Master to Reporting. As far as Rails is concerned, these were created via genuine rails commands and the Rails engine will make these models available in your reporting views and controllers. The
database.yml file will also make Rails point to the same database as Master.
Two rules need to be followed to make this work:
- All models or migrations are done in Master and only in Master. That includes any changes to model files.
- Run a
rake sync:copyevery once in a while to bring the Reporting project up to date after changes in Master.
- If you run
rake db:migratein the Reporting project, no harm will be done (because there are no migrations in it). But the
schema.rbfile will be regenerated. Which is cool.
- You can add additional projects that use the same shared model, I have 5 at the moment.
I could have just symlinked the model and db folders between the projects, and therefore not needed the
rake task. But that only works for a single development system and single developer. I would have to relink for each new computer or developer that needs to work on these projects.
I also could have used
git submodules to provide a common repository for the copied code, but that would mean that I could not use the regular
rake commands for models and migrations, which defeats the purpose of using Rails.
As a result of sharing (ok, copying) the models this way, I have several Rails applications running off different servers providing different services to different users all running off the same back-end database. Each application is smaller, simpler, easier to manage and easier to code and maintain. As long as discipline is maintained in that the models and migrations are only performed in the Master project, this trick works great.