Today, Craig White asks about svn and ruby structure:

When I set up the repository, I did an import of the entire base directory of the rails application which was great because it allowed me to do a checkout on to my computer with everything.

Of course, now on my home computer, I’ve got a changed database.yml and environment.rb and the log files (because I’ve been running a copy on my home system), and I would suspect that I really only want app and public directories (though the doc and plugins would be nice to manage with svn).

The most common problems Rails developers have with versioning their project are the config/database.yml file and log/ folder. Personally, I have found that doc/appdoc/ and doc/apidoc/ sometimes gets in the way. More on that later.

The following essay discusses how I manage my Rails projects with Subversion. It is assumed you already know about Rails and how to create new Rails applications. I also assume you have a working knowledge of Subversion. If you need help on using Subversion itself, you should really read one of these two books, ideally both:

If you are on a Windows machine, most of the commands will work as is. Notable exceptions are those that use the backquote (`), find, grep and the yes commands.

Pinkatio – our latest Rails application

We just had a killer idea to get us thousands of dollars of revenue per month. We will call it pinkatio, and we will put it on Rails.

Creating the Subversion repository

This is the most variable step in the whole procedure. If you know your way around a Unix/Linux system, go ahead and put the repository in /var. Watch your permissions, though. Else, I suggest sticking with a HOME based repository, like I did below. You can use the file repository access method. The only caveat is that you will not be able to share your repository with other people using that method.

To create the repository, we simply call svnadmin’s create subcommand:

To ease our poor fingers, let us create an environment variable to refer tot he repository’s root URL:

Subversion recommends creating all repositories with three folders at the root: trunk, tags and branches. This is if you use the one project per repository. This is explained in more details in Choosing a Repository Layout.

This is by no means a requirement to use Subversion, but I suggest sticking to this convention anyway. Most Subversion repositories I have seen adhere to the convention, and if you have only one project in your repository, it makes sense to be able to tag and branch at will.

$ svn mkdir—message=”Initial project layout” $REPOS/trunk $REPOS/tags $REPOS/branches Committed revision 1.

With the repository creation out of the way, let us now turn to creating our Rails application.

Creating the Rails application and importing into the repository

Creating the Rails application is straightforward:

At this point, you could do an svn import and import the whole application into Subversion. I recommend against doing that. If you use the “in-place import” procedure, you can commit only the pieces that you want, not the whole tree (log files being ones we don’t want under version control). See Subversion’s How can I do an in-place ‘import’ FAQ for the full details.

Next, let us add the whole tree to the working copy. This is no different than if we had done an svn import initially, except all changes are local, and we can selectively revert files and folders. The Rails command helpfully creates most of the tree. Since I use migrations in all of my Rails projects, I immediately create the db/migrate/ folder. Edge Rails and Rails 1.1 also include a tmp/ folder. For completeness’ sake, I create it at the same time.

Removing the log files from version control

Right now, Subversion will helpfully track changes to the log files. This is not really useful for us, as the log files can be pruned at any point.

To ease our burden, the easiest thing is to tell Subversion to ignore the logs.

See svn:ignore in the Subversion book for more details on the property format.

Managing the database configuration

Again the Subversion FAQ comes to the rescue: I have a file in my project that every developer must change, but I don’t want those local mods to ever be committed. How can I make ‘svn commit’ ignore the file?.

The solution is to have a template of the file in the repository, and to force each working copy to copy the template file to the real file. Let us simply revert the add of the config/database.yml file, and add a sample file instead:

The only problem with this procedure is if important changes are made to the config.yml.sample file, the developers might not notice the changes. Most of the time though, the sample file will not change, and leaving it as-is is ok.

Database structure dumps during testing

When you run the tests, Rails dumps the development database’s structure to a file in db/. Usually, this file should not be under version control. Your migration scripts should be under version control instead, and your migrations should enable you to recreate the development database at will.

Additionally, this step will depend on which configuration setting you use for the config.active_record.schema_format. If you use the :ruby (the default on Edge Rails and Rails 1.1), you should ignore the schema.rb file from db/. If you use :sql, simply ignore development_structure.sql instead. Alternatively, you could ignore both files, making this a moot point.

tmp/, documentation, scripts and public

Edge Rails and Rails 1.1 now possess a tmp/ folder. Since this folder will hold socket and session files, we can safely ignore everything in it.

The doc/ folder can hold two subfolders: appdoc/ and apidoc/. If you don’t plan on building the documentation for your project, you can ignore setting svn:ignore on doc/. Else, you should ignore like this:

Subversion also has a property that tells it which files are executable. We can set the property on files that are intended to be run from the command line:

Last but not least, my projects usually have a default home page served by a Rails action. This means building a route and removing public/index.html:

Saving our work

After all of these changes, it is important to commit our work to the repository.

After this step, it is time to start coding your application, unless you need to go on the Edge…

Using Rails Edge and protecting against overzealous gem upgrades

When you are going to put your application into production, you don’t want an upgrade in your host’s environment to affect your application. To prevent such problems, you should keep a local copy of Rails in your application’s vendor folder.

If you want to live on the Edge (with all the latest features), this step is a necessity. If you are not so comfortable with Edge, replace trunk/ with tags/rel_1-0-0 (or tags/rel_1-1-0 when Rails 1.1 is out) in the svn:externals property below.

If you went for Rails Edge, you should really rerun the rails . command after you update. This will ensure you get the latest version of the scripts and javascript files. And since we have not made any changes to the contents of any files, now is the best time to do this.

Don’t forget to commit your changes:

Tracking Edge Rails

Next time you svn update, Subversion will go out to the Rails repository and retrieve all changes since your last checkout. If the JavaScript files changed, you should copy them over using the rails:update Rake command:

Gems

Gem features a useful subcommand: unpack. When you run it on a gem, it will unpack that gem’s content into the current folder. We can then move the code to our vendor/ folder, and again protect ourselves against host upgrades.

As an example, let us unpack the Money gem:

Gems all have a lib/ folder into which the gem’s source code is stored. Copying the contents of the lib/ folder into vendor/ is the important trick here. If you move lib/ to vendor, it won’t help, as Rails automatic dependency loading mechanism will not know how to find your code.

At the same time, to comply with the library’s license, we copy the library verbatim to our vendor/ folder.

Let us tell Subversion what files we now want to version control: To help me remember which version I unpacked, I set a custom property on the main file of the library I just unpacked: Next, we cleanup after ourselves: Finally, let us commit our changes back to the repository.

Gem upgrades

When the next version of the Money gem will come around, we simply follow the same procedure as above. Of course, you will use svn status to know what files changed exactly. You might have to add new files, and remove old ones.

One tool that can help automate this process svn_load_dirs.pl, from the Subversion’s contrib/ area.

Plugins

For plugins, you have to take the same decision as for Rails – Edge or safe. For plugins, I have found that sticking to released version is safer for me. YMMV.

As an example, I will use the FileColumn plugin. Unfortunately, this plugin is not ready to be used by the script/plugin install -x procedure. So, we have to resort to a manual one.

Again, we must not forget to commit our changes to the repository:

Creating migrations, models and controllers

The Rails generate has a helpful option: --svn (-c):

All generate and destroy generators accept the --svn option. This makes it easy for the developer to keep his changes under version control.

Final words

I follow this script more or less verbatim for all of my Rails projects. After the first two or three times, this becomes automatic. For the adventurous, I have a shell script which does most of the steps above automatically. You can get rails2.sh.

rails2 license:
# Distributed in the Public Domain by Francois Beausoleil.
# This script might destroy twenty years worth of work, and I cannot be held
# responsible.  You are your own master.  Read this file in detail before
# you use it.
#
# NO IMPLIED WARRANTY.

10 Responses to “Subversion Primer for Rails projects”

  1. Ezra Zygmuntowicz Says:

    Very nice François! Thank you.

  2. Craig White Says:
    using tab completion on the line...
    REPOS=file://`pwd`/svn/pinkatio
    caused the command to switch and fail.
    
    also wondering if after running command,
    svn mkdir --message="Initial project layout" $REPOS/trunk $REPOS/tags $REPOS/branches
    
    if the directories would be visible because they didn't show up.
  3. Craig White Says:

    by the way…I failed to say…thanks, I needed this and it is very valuable to me.

  4. François Says:

    Craig, the “svn mkdir $REPOS/trunk” command is operating repository side, not working copy side. It is therefore correct to not see the folders in your current directory.

    Normally, you would never checkout the repository’s root directly, only trunk/ or tags/release-1.0.0 or even branches/adding-destabilizing-feature.

    Hope that clears things up !

  5. Jakob S Says:

    Thanks for writing this up, this is great :)

  6. Ben Askins Says:

    Thanks, this has come at just the right time.

  7. Tom Brice Says:

    Wow, thanks! This primer is GREAT!. I have never used Subversion for version control before. I’m pleased to say that now my app is under version control and I can breathe easier. This helped me not only do it but also understand what I was doing. Great work.

    This is a great example of how helpful and smart the Rails community is. Thanks again.

  8. Tasty Says:

    Thanks!!

  9. David Heinemeier Hansson Says:

    Great guide. For the record, though, I strongly recommend that you checkin your db/schema.rb file. It gives people who wants to start using the application at rev 50 less work to go through trying to migrate all the way from scratch. Especially since migrations often munge data as well.

  10. amiroff Says:

    Just discovered this great guide. Have no words but praise. Thank you very much for valuable information. This came out just in time.

Leave a Reply

 

Search

A picture of me

I am François Beausoleil, a Ruby on Rails coder. During the day, I work on XLsuite. At night, I am interested many things. Read my biography

Tags

(4) (1) (1) (1) (1) (2) (1) (1) (1) (2) (2) (1) (2) (1) (3) (1) (2) (1) (1) (1) (1) (2) (14) (1) (1) (1) (1) (2) (1) (1) (2) (0) (1) (4) (1) (3) (1) (1) (1) (1) (1) (1) (0) (3) (2) (1) (2) (1) (3) (1) (5) (2) (10) (10) (11) (14) (2) (1) (3) (1) (1) (1) (1) (1) (0) (1) (2) (2) (2) (1) (1) (1) (4) (1) (3) (1) (4) (2) (2) (25) (2) (1) (1) (0) (1) (1) (1) (23) (25) (1) (1) (13) (1) (1) (1) (4) (5) (1) (1) (1) (4) (1) (2) (3) (4) (4) (1) (1) (1) (8) (3) (1) (5) (5) (2) (2) (2) (4) (8) (7) (1) (1) (1) (1) (2) (4) (1) (4) (12) (2) (1) (2) (4) (1) (1) (1) (2) (8) (2) (3) (2) (2) (1) (3) (1) (1)

Links

Projects I work on

Categories

Archives