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
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 $@ }
With this function in our bash profile we can replace
rails -m
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.