aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source/generators.md
diff options
context:
space:
mode:
Diffstat (limited to 'guides/source/generators.md')
-rw-r--r--guides/source/generators.md147
1 files changed, 87 insertions, 60 deletions
diff --git a/guides/source/generators.md b/guides/source/generators.md
index d56bbe853c..e9c8ef0225 100644
--- a/guides/source/generators.md
+++ b/guides/source/generators.md
@@ -3,20 +3,18 @@ Creating and Customizing Rails Generators & Templates
Rails generators are an essential tool if you plan to improve your workflow. With this guide you will learn how to create generators and customize existing ones.
-In this guide you will:
+After reading this guide, you will know:
-* Learn how to see which generators are available in your application
-* Create a generator using templates
-* Learn how Rails searches for generators before invoking them
-* Customize your scaffold by creating new generators
-* Customize your scaffold by changing generator templates
-* Learn how to use fallbacks to avoid overwriting a huge set of generators
-* Learn how to create an application template
+* How to see which generators are available in your application.
+* How to create a generator using templates.
+* How Rails searches for generators before invoking them.
+* How to customize your scaffold by creating new generators.
+* How to customize your scaffold by changing generator templates.
+* How to use fallbacks to avoid overwriting a huge set of generators.
+* How to create an application template.
--------------------------------------------------------------------------------
-NOTE: This guide is about generators in Rails 3, previous versions are not covered.
-
First Contact
-------------
@@ -37,7 +35,7 @@ $ rails generate helper --help
Creating Your First Generator
-----------------------------
-Since Rails 3.0, generators are built on top of [Thor](https://github.com/wycats/thor). Thor provides powerful options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named `initializer.rb` inside `config/initializers`.
+Since Rails 3.0, generators are built on top of [Thor](https://github.com/erikhuda/thor). Thor provides powerful options parsing and a great API for manipulating files. For instance, let's build a generator that creates an initializer file named `initializer.rb` inside `config/initializers`.
The first step is to create a file at `lib/generators/initializer_generator.rb` with the following content:
@@ -49,7 +47,7 @@ class InitializerGenerator < Rails::Generators::Base
end
```
-NOTE: `create_file` is a method provided by `Thor::Actions`. Documentation for `create_file` and other Thor methods can be found in [Thor's documentation](http://rdoc.info/github/wycats/thor/master/Thor/Actions.html)
+NOTE: `create_file` is a method provided by `Thor::Actions`. Documentation for `create_file` and other Thor methods can be found in [Thor's documentation](http://rdoc.info/github/erikhuda/thor/master/Thor/Actions.html)
Our new generator is quite simple: it inherits from `Rails::Generators::Base` and has one method definition. When a generator is invoked, each public method in the generator is executed sequentially in the order that it is defined. Finally, we invoke the `create_file` method that will create a file at the given destination with the given content. If you are familiar with the Rails Application Templates API, you'll feel right at home with the new generators API.
@@ -164,7 +162,7 @@ Rails own generators are flexible enough to let you customize scaffolding. They
config.generators do |g|
g.orm :active_record
g.template_engine :erb
- g.test_framework :test_unit, :fixture => true
+ g.test_framework :test_unit, fixture: true
end
```
@@ -173,12 +171,13 @@ Before we customize our workflow, let's first see what our scaffold looks like:
```bash
$ rails generate scaffold User name:string
invoke active_record
- create db/migrate/20091120125558_create_users.rb
+ create db/migrate/20130924151154_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
- route resources :users
+ invoke resource_route
+ route resources :users
invoke scaffold_controller
create app/controllers/users_controller.rb
invoke erb
@@ -194,34 +193,50 @@ $ rails generate scaffold User name:string
create app/helpers/users_helper.rb
invoke test_unit
create test/helpers/users_helper_test.rb
- invoke stylesheets
- create app/assets/stylesheets/scaffold.css
+ invoke jbuilder
+ create app/views/users/index.json.jbuilder
+ create app/views/users/show.json.jbuilder
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/users.js.coffee
+ invoke scss
+ create app/assets/stylesheets/users.css.scss
+ invoke scss
+ create app/assets/stylesheets/scaffolds.css.scss
```
Looking at this output, it's easy to understand how generators work in Rails 3.0 and above. The scaffold generator doesn't actually generate anything, it just invokes others to do the work. This allows us to add/replace/remove any of those invocations. For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication.
-Our first customization on the workflow will be to stop generating stylesheets and test fixtures for scaffolds. We can achieve that by changing our configuration to the following:
+Our first customization on the workflow will be to stop generating stylesheets, javascripts and test fixtures for scaffolds. We can achieve that by changing our configuration to the following:
```ruby
config.generators do |g|
g.orm :active_record
g.template_engine :erb
- g.test_framework :test_unit, :fixture => false
+ g.test_framework :test_unit, fixture: false
g.stylesheets false
+ g.javascripts false
end
```
-If we generate another resource with the scaffold generator, we can see that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators.
+If we generate another resource with the scaffold generator, we can see that stylesheets, javascripts and fixtures are not created anymore. If you want to customize it further, for example to use DataMapper and RSpec instead of Active Record and TestUnit, it's just a matter of adding their gems to your application and configuring your generators.
To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator within the rails namespace, as this is where rails searches for generators used as hooks:
```bash
$ rails generate generator rails/my_helper
+ create lib/generators/rails/my_helper
+ create lib/generators/rails/my_helper/my_helper_generator.rb
+ create lib/generators/rails/my_helper/USAGE
+ create lib/generators/rails/my_helper/templates
```
-After that, we can delete both the `templates` directory and the `source_root` class method from our new generators, because we are not going to need them. So our new generator looks like the following:
+After that, we can delete both the `templates` directory and the `source_root`
+class method call from our new generator, because we are not going to need them.
+Add the method below, so our generator looks like the following:
```ruby
+# lib/generators/rails/my_helper/my_helper_generator.rb
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
def create_helper_file
create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
@@ -237,6 +252,7 @@ We can try out our new generator by creating a helper for users:
```bash
$ rails generate my_helper products
+ create app/helpers/products_helper.rb
```
And it will generate the following helper file in `app/helpers`:
@@ -253,8 +269,9 @@ Which is what we expected. We can now tell scaffold to use our new helper genera
config.generators do |g|
g.orm :active_record
g.template_engine :erb
- g.test_framework :test_unit, :fixture => false
+ g.test_framework :test_unit, fixture: false
g.stylesheets false
+ g.javascripts false
g.helper :my_helper
end
```
@@ -275,6 +292,7 @@ Since Rails 3.0, this is easy to do due to the hooks concept. Our new helper doe
To do that, we can change the generator this way:
```ruby
+# lib/generators/rails/my_helper/my_helper_generator.rb
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
def create_helper_file
create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
@@ -292,7 +310,7 @@ Now, when the helper generator is invoked and TestUnit is configured as the test
```ruby
# Search for :helper instead of :my_helper
-hook_for :test_framework, :as => :helper
+hook_for :test_framework, as: :helper
```
And now you can re-run scaffold for another resource and see it generating tests as well!
@@ -306,7 +324,7 @@ In Rails 3.0 and above, generators don't just look in the source root for templa
```erb
module <%= class_name %>Helper
- attr_reader :<%= plural_name %>, <%= plural_name.singularize %>
+ attr_reader :<%= plural_name %>, :<%= plural_name.singularize %>
end
```
@@ -316,8 +334,9 @@ and revert the last change in `config/application.rb`:
config.generators do |g|
g.orm :active_record
g.template_engine :erb
- g.test_framework :test_unit, :fixture => false
+ g.test_framework :test_unit, fixture: false
g.stylesheets false
+ g.javascripts false
end
```
@@ -334,8 +353,9 @@ We can easily simulate this behavior by changing our `config/application.rb` onc
config.generators do |g|
g.orm :active_record
g.template_engine :erb
- g.test_framework :shoulda, :fixture => false
+ g.test_framework :shoulda, fixture: false
g.stylesheets false
+ g.javascripts false
# Add a fallback!
g.fallbacks[:shoulda] = :test_unit
@@ -347,11 +367,12 @@ Now, if you create a Comment scaffold, you will see that the shoulda generators
```bash
$ rails generate scaffold Comment body:text
invoke active_record
- create db/migrate/20091120151323_create_comments.rb
+ create db/migrate/20130924143118_create_comments.rb
create app/models/comment.rb
invoke shoulda
create test/models/comment_test.rb
create test/fixtures/comments.yml
+ invoke resource_route
route resources :comments
invoke scaffold_controller
create app/controllers/comments_controller.rb
@@ -362,13 +383,19 @@ $ rails generate scaffold Comment body:text
create app/views/comments/show.html.erb
create app/views/comments/new.html.erb
create app/views/comments/_form.html.erb
- create app/views/layouts/comments.html.erb
invoke shoulda
create test/controllers/comments_controller_test.rb
invoke my_helper
create app/helpers/comments_helper.rb
invoke shoulda
create test/helpers/comments_helper_test.rb
+ invoke jbuilder
+ create app/views/comments/index.json.jbuilder
+ create app/views/comments/show.json.jbuilder
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/comments.js.coffee
+ invoke scss
```
Fallbacks allow your generators to have a single responsibility, increasing code reuse and reducing the amount of duplication.
@@ -376,18 +403,18 @@ Fallbacks allow your generators to have a single responsibility, increasing code
Application Templates
---------------------
-Now that you've seen how generators can be used _inside_ an application, did you know they can also be used to _generate_ applications too? This kind of generator is referred as a "template".
+Now that you've seen how generators can be used _inside_ an application, did you know they can also be used to _generate_ applications too? This kind of generator is referred as a "template". This is a brief overview of the Templates API. For detailed documentation see the [Rails Application Templates guide](rails_application_templates.html).
```ruby
-gem("rspec-rails", :group => "test")
-gem("cucumber-rails", :group => "test")
+gem "rspec-rails", group: "test"
+gem "cucumber-rails", group: "test"
if yes?("Would you like to install Devise?")
- gem("devise")
- generate("devise:install")
+ gem "devise"
+ generate "devise:install"
model_name = ask("What would you like the user model to be called? [user]")
model_name = "user" if model_name.blank?
- generate("devise", model_name)
+ generate "devise", model_name
end
```
@@ -404,7 +431,7 @@ This command will generate the `Thud` application, and then apply the template t
Templates don't have to be stored on the local system, the `-m` option also supports online templates:
```bash
-$ rails new thud -m https://gist.github.com/722911.txt
+$ rails new thud -m https://gist.github.com/radar/722911/raw/
```
Whilst the final section of this guide doesn't cover how to generate the most awesome template known to man, it will take you through the methods available at your disposal so that you can develop it yourself. These same methods are also available for generators.
@@ -414,15 +441,15 @@ Generator methods
The following are methods available for both generators and templates for Rails.
-NOTE: Methods provided by Thor are not covered this guide and can be found in [Thor's documentation](http://rdoc.info/github/wycats/thor/master/Thor/Actions.html)
+NOTE: Methods provided by Thor are not covered this guide and can be found in [Thor's documentation](http://rdoc.info/github/erikhuda/thor/master/Thor/Actions.html)
### `gem`
Specifies a gem dependency of the application.
```ruby
-gem("rspec", :group => "test", :version => "2.1.0")
-gem("devise", "1.1.5")
+gem "rspec", group: "test", version: "2.1.0"
+gem "devise", "1.1.5"
```
Available options are:
@@ -434,13 +461,13 @@ Available options are:
Any additional options passed to this method are put on the end of the line:
```ruby
-gem("devise", :git => "git://github.com/plataformatec/devise", :branch => "master")
+gem "devise", git: "git://github.com/plataformatec/devise", branch: "master"
```
The above code will put the following line into `Gemfile`:
```ruby
-gem "devise", :git => "git://github.com/plataformatec/devise", :branch => "master"
+gem "devise", git: "git://github.com/plataformatec/devise", branch: "master"
```
### `gem_group`
@@ -466,7 +493,7 @@ add_source "http://gems.github.com"
Injects a block of code into a defined position in your file.
```ruby
-inject_into_file 'name_of_file.rb', :after => "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
+inject_into_file 'name_of_file.rb', after: "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
puts "Hello World"
RUBY
end
@@ -503,7 +530,7 @@ Available options are:
* `:env` - Specify an environment for this configuration option. If you wish to use this option with the block syntax the recommended syntax is as follows:
```ruby
-application(nil, :env => "development") do
+application(nil, env: "development") do
"config.asset_host = 'http://localhost:3000'"
end
```
@@ -514,9 +541,9 @@ Runs the specified git command:
```ruby
git :init
-git :add => "."
-git :commit => "-m First commit!"
-git :add => "onefile.rb", :rm => "badfile.cxx"
+git add: "."
+git commit: "-m First commit!"
+git add: "onefile.rb", rm: "badfile.cxx"
```
The values of the hash here being the arguments or options passed to the specific git command. As per the final example shown here, multiple git commands can be specified at a time, but the order of their running is not guaranteed to be the same as the order that they were specified in.
@@ -526,13 +553,13 @@ The values of the hash here being the arguments or options passed to the specifi
Places a file into `vendor` which contains the specified code.
```ruby
-vendor("sekrit.rb", '#top secret stuff')
+vendor "sekrit.rb", '#top secret stuff'
```
This method also takes a block:
```ruby
-vendor("seeds.rb") do
+vendor "seeds.rb" do
"puts 'in ur app, seeding ur database'"
end
```
@@ -542,13 +569,13 @@ end
Places a file into `lib` which contains the specified code.
```ruby
-lib("special.rb", 'p Rails.root')
+lib "special.rb", "p Rails.root"
```
This method also takes a block:
```ruby
-lib("super_special.rb") do
+lib "super_special.rb" do
puts "Super special!"
end
```
@@ -558,15 +585,15 @@ end
Creates a Rake file in the `lib/tasks` directory of the application.
```ruby
-rakefile("test.rake", 'hello there')
+rakefile "test.rake", "hello there"
```
This method also takes a block:
```ruby
-rakefile("test.rake") do
+rakefile "test.rake" do
%Q{
- task :rock => :environment do
+ task rock: :environment do
puts "Rockin'"
end
}
@@ -578,14 +605,14 @@ end
Creates an initializer in the `config/initializers` directory of the application:
```ruby
-initializer("begin.rb", "puts 'this is the beginning'")
+initializer "begin.rb", "puts 'this is the beginning'"
```
-This method also takes a block:
+This method also takes a block, expected to return a string:
```ruby
-initializer("begin.rb") do
- puts "Almost done!"
+initializer "begin.rb" do
+ "puts 'this is the beginning'"
end
```
@@ -594,7 +621,7 @@ end
Runs the specified generator where the first argument is the generator name and the remaining arguments are passed directly to the generator.
```ruby
-generate("scaffold", "forums title:string description:text")
+generate "scaffold", "forums title:string description:text"
```
@@ -603,7 +630,7 @@ generate("scaffold", "forums title:string description:text")
Runs the specified Rake task.
```ruby
-rake("db:migrate")
+rake "db:migrate"
```
Available options are:
@@ -624,7 +651,7 @@ capify!
Adds text to the `config/routes.rb` file:
```ruby
-route("resources :people")
+route "resources :people"
```
### `readme`
@@ -632,5 +659,5 @@ route("resources :people")
Output the contents of a file in the template's `source_path`, usually a README.
```ruby
-readme("README")
+readme "README"
```