homeASCIIcasts

148: App Templates in Rails 2.3 

(view original Railscast)

Rails 2.3 will be here soon, so the next few episodes are about some of the new features it provides. First we’ll demonstrate Application Templates which provide a way of automating some of the common steps we have to go through when creating a new Rails app.

Installing Rails 2.3

At the time of writing, Rails 2.3 is still at the Release Candidate stage. We can install it from http://gems.rubyonrails.org.

sudo gem install rails --source http://gems.rubyonrails.org

Once its installed we’ll check that we have the correct version and we can begin.

NooNoo:~ eifion$ rails -v
Rails 2.3.0

What Are Templates?

Usually, when we talk about templates in Rails we mean the files that live under the views folder that provide templates for generating HMTL, XML etc. Application templates are completely different, they are Ruby scripts that help to automate common tasks when we’re generating a new Rails application. For example, we might want to add the new application to a git repository, or install some plugins or gems. Application templates can automate all of this for us.

Creating a Template

Application templates are simply Ruby scripts, but they have access to several methods that enable us to write the scripts almost as if we were using a domain specific language. We’re going to create one called base_template.rb so that we can demonstrate some of these methods.

run

As its name implies we can use the run command to run commands on the system. The run command below uses echo to reduce the size of the README file that is generated when we create a new Rails app.

run "echo TODO > README"

Now, when a new Rails application is generated with our template the contents of the README file will be replaced with the word TODO. To see if our template is working we’ll create a new Rails app that runs it. To tell rails to use a template we just pass -m and the name of the template file.

eifion$ rails -m base_template.rb testapp
    create  
    create  app/controllers
    ...
    <large number of lines snipped>
    ...
    applying  template: base_template.rb
    executing  echo TODO > README from /Users/eifion/rails/
eifion$ cat testapp/README 
TODO

Generating an application with our template file.

From the output above we can see that our template has been applied and the echo command executed. We’ve then used cat to view the contents of the README file.

git and file

When we create a new Rails app we usually add it to a new git repository. There’s a git method to do this.

git :init
git :add => ".", :commit => "-m 'initial commit.'"

The first line above creates a new git repository and the second adds all of the files and then makes the initial commit. Note that if we want to add arguments to each command we pass the command as a hash and that we can run multiple git commands by passing more than one argument.

If we’re creating a git repository then we’ll want a .gitignore file to go with it. The file command will create it for us.

file ".gitignore", <<-END
.DS_Store
log/*.log
tmp/**/*
config/database.yml
db/*.sqlite3
END

There’s one more thing we want to do before we make our first git commit. We’ll use run again to create some .gitignore files and make a copy of our database.yml file. The two lines below should be placed just before the git add and commit commands are run.

run "touch tmp/.gitignore log/.gitignore vendor/.gitignore"
run "cp config/database.yml config/example_database.yml"

When we create an application with our template now we’ll see the git repository created.

applying  template: base_template.rb
executing  echo TODO > README from /Users/eifion/rails/apps_for_asciicasts/testapp
running  git init
file  .gitignore
executing  touch tmp/.gitignore log/.gitignore vendor/.gitignore from /Users/eifion/rails/apps_for_asciicasts/testapp
executing  cp config/database.yml config/example_database.yml from /Users/eifion/rails/apps_for_asciicasts/testapp
running  git add .
running  git commit -m ’initial commit.’
applied  base_template.rb

Our template file now creates a git repository for us.

The template will now automatically set up a git repository for us and commit the files from our new application.

generate

We might also want to run some script/generate commands when we create a new application. Ryan Bates has a generator called nifty-generators that he uses on each of his applications. We can run a generator in our application template with the generate command.

generate :nifty-layout, "with_some_arguments"

We can pass additional arguments to the generator if we need too by supplying them as a second argument.

gem

It’s fairly common to want to add some gems to a new Rails app and there’s a gem method for doing that. The arguments we pass are the same as we’d pass to the config.gem method in our environment.rb file.

gem 'RedCloth', :lib => 'redcloth'
gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com'

Adding gems with our template.

rake

As well as specifying gems it would be useful to have them installed by the template. We can do this or run any other rake task with the rake method. To install our gems we’ll add this line after the two above.

rake gems:install

plugin

The plugin method installs plugins, such as RSpec. We just specify the name of the plugin and the URL of the repository and then run the generate command to run the RSpec generator script.

plugin "rspec", :git => "git://github.com/dchelimsky/rspec.git"
plugin "rspec-rails", :git => "git://github.com/dchelimsky/rspec-rails.git"
generate :rspec

Adding Conditions

There might be a part of the script that we don’t want to run every time. We can use the yes? method to ask whether or not a part of a script should be run. If we don’t always want to run the RSpec commands above then we can wrap them in an if statement and the template will ask us to confirm whether to run that part of the template.

if yes?("Do you want to use RSpec?")
  plugin "rspec", :git => "git://github.com/dchelimsky/rspec.git"
  plugin "rspec-rails", :git => "git://github.com/dchelimsky/rspec-rails.git"
  generate :rspec
end

Using yes? to confirm part of the script.

When we run our script now we’ll be asked if we want to install RSpec or not.

  rake  gems:install
    Do you want to use RSpec?
yes
  plugin  rspec
  From git://github.com/dchelimsky/rspec
   * branch            HEAD       -> FETCH_HEAD
  plugin  rspec-rails
  From git://github.com/dchelimsky/rspec-rails
   * branch            HEAD       -> FETCH_HEAD
  generating  rspec

Using More Than One Script

We now have a application template script that we’re happy with, but what if we sometimes want to perform additional setup tasks, such as adding user authentication? We could use yes? again and ask each time, or we could use a separate template. We’re going to take the latter option and create another template called auth_template.rb. Our authentication template is going to need to do all of the things that our base template does but we don’t really want to copy all of that script into our new one. Instead, we can load the base template in our authentication template using load_template.

load_template "/Users/eifion/rails/base_template.rb"

Note that we have to supply the full path to the other template.

To create our authentication we’ll use another of Ryan Bates’ plugins, one called nifty_authentication. This plugin needs a parameter: the name of the first user to be generated. There’s an ask method that will do this for us. ask differs from yes? in that it returns a string instead of a boolean value which we can pass to the plugin.

name = ask("What would you like the user to be called?")
generate :nifty_authentication, name
rake "db:migrate"
git :add => ".", :commit => "-m 'adding authentication'"

Once we’ve generated our authentication system the script runs our migrations and commit the changes to our git repository.

Generating The Home Page

We’re almost there with our script now but it would be good if we could get it to generate a default controller and remove the default index page that rails creates. With a combination of the route and generate commands we can.

generate :controller, "welcome index"
route "map.root :controller => 'welcome'"
git :rm => "public/index.html"
git :add => ".", :commit => "-m 'adding welcome controller.'"

We used generate earlier, but here we’re using it to generate a controller. We’re then using route to add a line to routes.rb to define a default route before using git to remove the default home page and making a commit.

The output from our new script looks like this (the parts from the included base_template.rb aren’t shown). We’re asked for a name for our user and then the rest of the script runs automatically.

  What would you like the user to be called?
Bob
  generating  nifty_authentication
        rake  db:migrate
     running  git add .
     running  git commit -m ’adding authentication’
  generating  controller
       route  map.root :controller => ’welcome’
     running  git rm public/index.html
     running  git add .
     running  git commit -m ’adding welcome controller.’
     applied  auth_template.rb

Organising Our Templates

Application templates are a powerful addition to Rails, but storing them on your local machine makes them less portable than they could be, especially if you’re including one template in the other and having to specify the full path. A good alternative is to store your templates in a GitHub account. That way they can be specified by a URL rather than a file path. The -m option will take a URL instead of a filename so once we’ve uploaded our templates to GitHub we can call our templates this way.

rails testapp -m http://github.com/eifion/rails-templates/raw/master/base_template.rb

We can also use a url when calling the load_template method which solves the problem of having to supply a full path.

Finally, we could take things a step further and create a function in our ~/.bash_profile file to create a command that will automatically create a Rails app with a specified template.

function railsapp {
  template=$1
  appname=$2
  shift 2
  rails $appname -m http://github.com/eifion/rails-templates/raw/master/$template.rb $@
}

With this function in our bash profile we can replace

rails -m http://github.com/eifion/rails-templates/raw/master/auth_template.rb testapp

with

railsapp auth_template testapp

Further Reading

There’s a lot more to Rails templates that we’ve been able to cover here. There’s more about the templates on Pratik Naik’s blog. Also, there are a number of templates available on Jeremy McAnally’s GitHub repository.