railties 3.0.0.beta4 → 3.0.0.rc
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +24 -6
- data/README.rdoc +25 -0
- data/guides/assets/javascripts/code_highlighter.js +0 -0
- data/guides/assets/javascripts/guides.js +0 -0
- data/guides/assets/stylesheets/print.css +0 -0
- data/guides/assets/stylesheets/reset.css +0 -0
- data/guides/assets/stylesheets/style.css +0 -0
- data/guides/source/3_0_release_notes.textile +5 -3
- data/guides/source/action_controller_overview.textile +19 -0
- data/guides/source/active_record_basics.textile +27 -21
- data/guides/source/active_record_querying.textile +39 -37
- data/guides/source/{activerecord_validations_callbacks.textile → active_record_validations_callbacks.textile} +30 -29
- data/guides/source/active_support_core_extensions.textile +232 -107
- data/guides/source/api_documentation_guidelines.textile +187 -0
- data/guides/source/association_basics.textile +45 -1
- data/guides/source/configuring.textile +7 -7
- data/guides/source/contributing_to_rails.textile +42 -15
- data/guides/source/form_helpers.textile +1 -1
- data/guides/source/generators.textile +37 -37
- data/guides/source/getting_started.textile +11 -11
- data/guides/source/i18n.textile +1 -1
- data/guides/source/index.html.erb +14 -6
- data/guides/source/initialization.textile +130 -124
- data/guides/source/layout.html.erb +5 -2
- data/guides/source/layouts_and_rendering.textile +2 -2
- data/guides/source/migrations.textile +4 -3
- data/guides/source/plugins.textile +15 -15
- data/guides/source/rails_application_templates.textile +2 -2
- data/guides/source/routing.textile +83 -62
- data/guides/source/security.textile +2 -2
- data/guides/w3c_validator.rb +30 -6
- data/lib/rails.rb +3 -3
- data/lib/rails/application.rb +43 -19
- data/lib/rails/application/bootstrap.rb +2 -0
- data/lib/rails/application/configuration.rb +3 -3
- data/lib/rails/application/finisher.rb +6 -6
- data/lib/rails/cli.rb +1 -19
- data/lib/rails/commands.rb +5 -5
- data/lib/rails/commands/application.rb +1 -1
- data/lib/rails/commands/console.rb +1 -4
- data/lib/rails/commands/generate.rb +0 -0
- data/lib/rails/commands/plugin.rb +57 -52
- data/lib/rails/commands/runner.rb +2 -1
- data/lib/rails/commands/server.rb +6 -2
- data/lib/rails/configuration.rb +2 -3
- data/lib/rails/console/app.rb +0 -2
- data/lib/rails/engine.rb +14 -15
- data/lib/rails/engine/configuration.rb +5 -5
- data/lib/rails/generators.rb +2 -3
- data/lib/rails/generators/actions.rb +4 -4
- data/lib/rails/generators/base.rb +1 -1
- data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +1 -6
- data/lib/rails/generators/erb/scaffold/templates/_form.html.erb +4 -4
- data/lib/rails/generators/erb/scaffold/templates/edit.html.erb +3 -3
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +7 -7
- data/lib/rails/generators/erb/scaffold/templates/new.html.erb +2 -2
- data/lib/rails/generators/erb/scaffold/templates/show.html.erb +3 -3
- data/lib/rails/generators/generated_attribute.rb +2 -1
- data/lib/rails/generators/named_base.rb +24 -0
- data/lib/rails/generators/rails/app/app_generator.rb +10 -9
- data/lib/rails/generators/rails/app/templates/Gemfile +4 -3
- data/lib/rails/generators/rails/app/templates/README +6 -31
- data/lib/rails/generators/rails/app/templates/Rakefile +1 -1
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb +0 -1
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/config/application.rb +11 -11
- data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +36 -24
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +3 -0
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +3 -0
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +3 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +2 -2
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +2 -2
- data/lib/rails/generators/rails/app/templates/config/routes.rb +1 -1
- data/lib/rails/generators/rails/app/templates/public/index.html +0 -17
- data/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js +2027 -900
- data/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +114 -57
- data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +1 -1
- data/lib/rails/generators/rails/model/USAGE +1 -1
- data/lib/rails/generators/rails/resource/resource_generator.rb +4 -14
- data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +0 -2
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +28 -30
- data/lib/rails/generators/resource_helpers.rb +1 -1
- data/lib/rails/generators/test_case.rb +25 -11
- data/lib/rails/generators/test_unit/model/model_generator.rb +1 -1
- data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +0 -1
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +13 -15
- data/lib/rails/info.rb +1 -2
- data/lib/rails/info_routes.rb +1 -1
- data/lib/rails/initializable.rb +3 -16
- data/lib/rails/paths.rb +31 -36
- data/lib/rails/plugin.rb +10 -6
- data/lib/rails/rack/logger.rb +11 -13
- data/lib/rails/railtie.rb +14 -42
- data/lib/rails/ruby_version_check.rb +19 -5
- data/lib/rails/script_rails_loader.rb +29 -0
- data/lib/rails/tasks/annotations.rake +2 -2
- data/lib/rails/tasks/documentation.rake +47 -16
- data/lib/rails/tasks/framework.rake +9 -9
- data/lib/rails/tasks/middleware.rake +1 -1
- data/lib/rails/tasks/misc.rake +5 -5
- data/lib/rails/tasks/routes.rake +1 -1
- data/lib/rails/tasks/tmp.rake +5 -5
- data/lib/rails/test_unit/testing.rake +38 -14
- data/lib/rails/version.rb +1 -1
- metadata +29 -17
- data/README +0 -281
- data/lib/rails/application/routes_reloader.rb +0 -46
- data/lib/rails/log_subscriber.rb +0 -115
- data/lib/rails/log_subscriber/test_helper.rb +0 -97
- data/lib/rails/webrick_server.rb +0 -156
@@ -0,0 +1,187 @@
|
|
1
|
+
h2. API Documentation Guidelines
|
2
|
+
|
3
|
+
This guide documents the Ruby on Rails API documentation guidelines.
|
4
|
+
|
5
|
+
endprologue.
|
6
|
+
|
7
|
+
h3. RDoc
|
8
|
+
|
9
|
+
The Rails API documentation is generated with RDoc 2.5. Please consult the "RDoc documentation":http://rdoc.rubyforge.org/RDoc.htmlFor for help with its markup.
|
10
|
+
|
11
|
+
h3. Wording
|
12
|
+
|
13
|
+
Write simple, declarative sentences. Brevity is a plus: get to the point.
|
14
|
+
|
15
|
+
Write in present tense: "Returns a hash that...", rather than "Returned a hash that..." or "Will return a hash that...".
|
16
|
+
|
17
|
+
Start comments in upper case, follow regular punctuation rules:
|
18
|
+
|
19
|
+
<ruby>
|
20
|
+
# Declares an attribute reader backed by an internally-named instance variable.
|
21
|
+
def attr_internal_reader(*attrs)
|
22
|
+
...
|
23
|
+
end
|
24
|
+
</ruby>
|
25
|
+
|
26
|
+
Communicate to the reader the current way of doing things, both explicitly and implicitly. Use the recommended idioms in edge, reorder sections to emphasize favored approaches if needed, etc. The documentation should be a model for best practices and canonical, modern Rails usage.
|
27
|
+
|
28
|
+
Documentation has to be concise but comprehensive. Explore and document edge cases. What happens if a module is anonymous? What if a collection is empty? What if an argument is nil?
|
29
|
+
|
30
|
+
The proper names of Rails components have a space in between the words, like "Active Support". +ActiveRecord+ is a Ruby module, whereas Active Record is an ORM. Historically there has been lack of consistency regarding this, but we checked with David when docrails started. All Rails documentation consistently refer to Rails components by their proper name, and if in your next blog post or presentation you remember this tidbit and take it into account that'd be fenomenal :).
|
31
|
+
|
32
|
+
Spell names correctly: HTML, MySQL, JavaScript, ERb.
|
33
|
+
|
34
|
+
h3. Example Code
|
35
|
+
|
36
|
+
Choose meaningful examples that depict and cover the basics as well as interesting points or gotchas.
|
37
|
+
|
38
|
+
Use two spaces to indent chunks of code.—that is two spaces with respect to the left margin; the examples
|
39
|
+
themselves should use "Rails code conventions":http://rails.lighthouseapp.com/projects/8994/source-style.
|
40
|
+
|
41
|
+
Short docs do not need an explicit "Examples" label to introduce snippets, they just follow paragraphs:
|
42
|
+
|
43
|
+
<ruby>
|
44
|
+
# Converts a collection of elements into a formatted string by calling
|
45
|
+
# <tt>to_s</tt> on all elements and joining them.
|
46
|
+
#
|
47
|
+
# Blog.find(:all).to_formatted_s # => "First PostSecond PostThird Post"
|
48
|
+
</ruby>
|
49
|
+
|
50
|
+
On the other hand big chunks of structured documentation may have a separate "Examples" section:
|
51
|
+
|
52
|
+
<ruby>
|
53
|
+
# ==== Examples
|
54
|
+
#
|
55
|
+
# Person.exists?(5)
|
56
|
+
# Person.exists?('5')
|
57
|
+
# Person.exists?(:name => "David")
|
58
|
+
# Person.exists?(['name LIKE ?', "%#{query}%"])
|
59
|
+
</ruby>
|
60
|
+
|
61
|
+
The result of expressions follow them and are introduced by "# => ", vertically aligned:
|
62
|
+
|
63
|
+
<ruby>
|
64
|
+
# For checking if a fixnum is even or odd.
|
65
|
+
#
|
66
|
+
# 1.even? # => false
|
67
|
+
# 1.odd? # => true
|
68
|
+
# 2.even? # => true
|
69
|
+
# 2.odd? # => false
|
70
|
+
</ruby>
|
71
|
+
|
72
|
+
If a line is too long, the comment may be placed on the next line:
|
73
|
+
|
74
|
+
<ruby>
|
75
|
+
# label(:post, :title)
|
76
|
+
# # => <label for="post_title">Title</label>
|
77
|
+
#
|
78
|
+
# label(:post, :title, "A short title")
|
79
|
+
# # => <label for="post_title">A short title</label>
|
80
|
+
#
|
81
|
+
# label(:post, :title, "A short title", :class => "title_label")
|
82
|
+
# # => <label for="post_title" class="title_label">A short title</label>
|
83
|
+
</ruby>
|
84
|
+
|
85
|
+
Avoid using any printing methods like +puts+ or +p+ for that purpose.
|
86
|
+
|
87
|
+
On the other hand, regular comments do not use an arrow:
|
88
|
+
|
89
|
+
<ruby>
|
90
|
+
# polymorphic_url(record) # same as comment_url(record)
|
91
|
+
</ruby>
|
92
|
+
|
93
|
+
h3. Filenames
|
94
|
+
|
95
|
+
As a rule of thumb use filenames relative to the application root:
|
96
|
+
|
97
|
+
<plain>
|
98
|
+
config/routes.rb # YES
|
99
|
+
routes.rb # NO
|
100
|
+
RAILS_ROOT/config/routes.rb # NO
|
101
|
+
</plain>
|
102
|
+
|
103
|
+
|
104
|
+
h3. Fonts
|
105
|
+
|
106
|
+
h4. Fixed-width Font
|
107
|
+
|
108
|
+
Use fixed-width fonts for:
|
109
|
+
* constants, in particular class and module names
|
110
|
+
* method names
|
111
|
+
* literals like +nil+, +false+, +true+, +self+
|
112
|
+
* symbols
|
113
|
+
* method parameters
|
114
|
+
* file names
|
115
|
+
|
116
|
+
<ruby>
|
117
|
+
# Copies the instance variables of +object+ into +self+.
|
118
|
+
#
|
119
|
+
# Instance variable names in the +exclude+ array are ignored. If +object+
|
120
|
+
# responds to <tt>protected_instance_variables</tt> the ones returned are
|
121
|
+
# also ignored. For example, Rails controllers implement that method.
|
122
|
+
# ...
|
123
|
+
def copy_instance_variables_from(object, exclude = [])
|
124
|
+
...
|
125
|
+
end
|
126
|
+
</ruby>
|
127
|
+
|
128
|
+
WARNING: Using a pair of ++...++ for fixed-width font only works with *words*; that is: anything matching <tt>\A\w+\z</tt>. For anything else use +<tt>...</tt>+, notably symbols, setters, inline snippets, etc:
|
129
|
+
|
130
|
+
h4. Regular Font
|
131
|
+
|
132
|
+
When "true" and "false" are English words rather than Ruby keywords use a regular font:
|
133
|
+
|
134
|
+
<ruby>
|
135
|
+
# If <tt>reload_plugins?</tt> is false, add this to your plugin's <tt>init.rb</tt>
|
136
|
+
# to make it reloadable:
|
137
|
+
#
|
138
|
+
# Dependencies.load_once_paths.delete lib_path
|
139
|
+
</ruby>
|
140
|
+
|
141
|
+
h3. Description Lists
|
142
|
+
|
143
|
+
In lists of options, parameters, etc. use a hyphen between the item and its description (reads better than a colon because normally options are symbols):
|
144
|
+
|
145
|
+
<ruby>
|
146
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
147
|
+
</ruby>
|
148
|
+
|
149
|
+
The description starts in upper case and ends with a full stop—it's standard English.
|
150
|
+
|
151
|
+
h3. Dynamically Generated Methods
|
152
|
+
|
153
|
+
Methods created with +(module|class)_eval(STRING)+ have a comment by their side with an instance of the generated code. That comment is 2 spaces apart from the template:
|
154
|
+
|
155
|
+
<ruby>
|
156
|
+
for severity in Severity.constants
|
157
|
+
class_eval <<-EOT, __FILE__, __LINE__
|
158
|
+
def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
|
159
|
+
add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
|
160
|
+
end # end
|
161
|
+
#
|
162
|
+
def #{severity.downcase}? # def debug?
|
163
|
+
#{severity} >= @level # DEBUG >= @level
|
164
|
+
end # end
|
165
|
+
EOT
|
166
|
+
end
|
167
|
+
</ruby>
|
168
|
+
|
169
|
+
If the resulting lines are too wide, say 200 columns or more, we put the comment above the call:
|
170
|
+
|
171
|
+
<ruby>
|
172
|
+
# def self.find_by_login_and_activated(*args)
|
173
|
+
# options = args.extract_options!
|
174
|
+
# ...
|
175
|
+
# end
|
176
|
+
self.class_eval %{
|
177
|
+
def self.#{method_id}(*args)
|
178
|
+
options = args.extract_options!
|
179
|
+
...
|
180
|
+
end
|
181
|
+
}
|
182
|
+
</ruby>
|
183
|
+
|
184
|
+
h3. Changelog
|
185
|
+
|
186
|
+
* July 17, 2010: ported from the docrails wiki and revised by "Xavier Noria":credits.html#fxn
|
187
|
+
|
@@ -137,6 +137,16 @@ end
|
|
137
137
|
|
138
138
|
!images/has_many_through.png(has_many :through Association Diagram)!
|
139
139
|
|
140
|
+
The collection of join models can be managed via the API. For example, if you assign
|
141
|
+
|
142
|
+
<ruby>
|
143
|
+
physician.patients = patients
|
144
|
+
</ruby>
|
145
|
+
|
146
|
+
new join models are created for newly associated objects, and if some are gone their rows are deleted.
|
147
|
+
|
148
|
+
WARNING: Automatic deletion of join models is direct, no destroy callbacks are triggered.
|
149
|
+
|
140
150
|
The +has_many :through+ association is also useful for setting up "shortcuts" through nested +has_many+ associations. For example, if a document has many sections, and a section has many paragraphs, you may sometimes want to get a simple collection of all paragraphs in the document. You could set that up this way:
|
141
151
|
|
142
152
|
<ruby>
|
@@ -1361,7 +1371,41 @@ The +:through+ option specifies a join model through which to perform the query.
|
|
1361
1371
|
|
1362
1372
|
h6(#has_many-uniq). +:uniq+
|
1363
1373
|
|
1364
|
-
|
1374
|
+
Set the +:uniq+ option to true to keep the collection free of duplicates. This is mostly useful together with the +:through+ option.
|
1375
|
+
|
1376
|
+
<ruby>
|
1377
|
+
class Person < ActiveRecord::Base
|
1378
|
+
has_many :readings
|
1379
|
+
has_many :posts, :through => :readings
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
person = Person.create(:name => 'john')
|
1383
|
+
post = Post.create(:name => 'a1')
|
1384
|
+
person.posts << post
|
1385
|
+
person.posts << post
|
1386
|
+
person.posts.inspect # => [#<Post id: 5, name: "a1">, #<Post id: 5, name: "a1">]
|
1387
|
+
Reading.all.inspect # => [#<Reading id: 12, person_id: 5, post_id: 5>, #<Reading id: 13, person_id: 5, post_id: 5>]
|
1388
|
+
</ruby>
|
1389
|
+
|
1390
|
+
In the above case there are two readings and +person.posts+ brings out both of them even though these records are pointing to the same post.
|
1391
|
+
|
1392
|
+
Now let's set +:uniq+ to true:
|
1393
|
+
|
1394
|
+
<ruby>
|
1395
|
+
class Person
|
1396
|
+
has_many :readings
|
1397
|
+
has_many :posts, :through => :readings, :uniq => true
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
person = Person.create(:name => 'honda')
|
1401
|
+
post = Post.create(:name => 'a1')
|
1402
|
+
person.posts << post
|
1403
|
+
person.posts << post
|
1404
|
+
person.posts.inspect # => [#<Post id: 7, name: "a1">]
|
1405
|
+
Reading.all.inspect # => [#<Reading id: 16, person_id: 7, post_id: 7>, #<Reading id: 17, person_id: 7, post_id: 7>]
|
1406
|
+
</ruby>
|
1407
|
+
|
1408
|
+
In the above case there are still two readings. However +person.posts+ shows only one post because the collection loads only unique records.
|
1365
1409
|
|
1366
1410
|
h6(#has_many-validate). +:validate+
|
1367
1411
|
|
@@ -135,7 +135,7 @@ h4. Configuring Action Controller
|
|
135
135
|
|
136
136
|
* +config.action_controller.allow_concurrency+ should be set to +true+ to allow concurrent (threadsafe) action processing. Set to +false+ by default. You probably don't want to call this one directly, though, because a series of other adjustments need to be made for threadsafe mode to work properly. Instead, you should simply call +config.threadsafe!+ inside your +production.rb+ file, which makes all the necessary adjustments.
|
137
137
|
|
138
|
-
WARNING: Threadsafe operation
|
138
|
+
WARNING: Threadsafe operation is incompatible with the normal workings of development mode Rails. In particular, automatic dependency loading and class reloading are automatically disabled when you call +config.threadsafe!+.
|
139
139
|
|
140
140
|
* +config.action_controller.param_parsers+ provides an array of handlers that can extract information from incoming HTTP requests and add it to the +params+ hash. By default, parsers for multipart forms, URL-encoded forms, XML, and JSON are active.
|
141
141
|
|
@@ -167,9 +167,9 @@ The caching code adds two additional settings:
|
|
167
167
|
|
168
168
|
The Active Record session store can also be configured:
|
169
169
|
|
170
|
-
* +ActiveRecord::SessionStore::Session.table_name+ sets the name of the table
|
170
|
+
* +ActiveRecord::SessionStore::Session.table_name+ sets the name of the table used to store sessions. Defaults to +sessions+.
|
171
171
|
|
172
|
-
* +ActiveRecord::SessionStore::Session.primary_key+ sets the name of the ID column
|
172
|
+
* +ActiveRecord::SessionStore::Session.primary_key+ sets the name of the ID column used in the sessions table. Defaults to +session_id+.
|
173
173
|
|
174
174
|
* +ActiveRecord::SessionStore::Session.data_column_name+ sets the name of the column which stores marshaled session data. Defaults to +data+.
|
175
175
|
|
@@ -181,7 +181,7 @@ There are only a few configuration options for Action View, starting with four o
|
|
181
181
|
|
182
182
|
* +config.action_view.warn_cache_misses+ tells Rails to display a warning whenever an action results in a cache miss on your view paths. The default is +false+.
|
183
183
|
|
184
|
-
* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is <tt>Proc.new{ |html_tag, instance| "<div class=\"
|
184
|
+
* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is <tt>Proc.new{ |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>" }</tt>
|
185
185
|
|
186
186
|
* +config.action_view.default_form_builder+ tells Rails which form builder to use by default. The default is +ActionView::Helpers::FormBuilder+.
|
187
187
|
|
@@ -235,9 +235,9 @@ h4. Configuring Active Support
|
|
235
235
|
|
236
236
|
There are a few configuration options available in Active Support:
|
237
237
|
|
238
|
-
* +config.active_support.escape_html_entities_in_json+ enables or disables the escaping of HTML entities in JSON serialization. Defaults to
|
238
|
+
* +config.active_support.escape_html_entities_in_json+ enables or disables the escaping of HTML entities in JSON serialization. Defaults to +true+.
|
239
239
|
|
240
|
-
* +config.active_support.use_standard_json_time_format+ enables or disables serializing dates to ISO 8601 format. Defaults to
|
240
|
+
* +config.active_support.use_standard_json_time_format+ enables or disables serializing dates to ISO 8601 format. Defaults to +false+.
|
241
241
|
|
242
242
|
* +ActiveSupport::BufferedLogger.silencer+ is set to +false+ to disable the ability to silence logging in a block. The default is +true+.
|
243
243
|
|
@@ -247,7 +247,7 @@ There are a few configuration options available in Active Support:
|
|
247
247
|
|
248
248
|
h3. Using Initializers
|
249
249
|
|
250
|
-
After
|
250
|
+
After loading the framework and any gems and plugins in your application, Rails turns to loading initializers. An initializer is any file of Ruby code stored under +config/initializers+ in your application. You can use initializers to hold configuration settings that should be made after all of the frameworks and plugins are loaded.
|
251
251
|
|
252
252
|
NOTE: You can use subfolders to organize your initializers if you like, because Rails will look into the whole file hierarchy from the +initializers+ folder on down.
|
253
253
|
|
@@ -62,26 +62,39 @@ git clone git://github.com/rails/rails.git
|
|
62
62
|
cd rails
|
63
63
|
</shell>
|
64
64
|
|
65
|
-
h4.
|
65
|
+
h4. Set up and Run the Tests
|
66
66
|
|
67
|
-
|
67
|
+
All of the Rails tests must pass with any code you submit, otherwise you have no chance of getting code accepted. This means you need to be able to run the tests. First, you need to install all Rails dependencies with bundler:
|
68
68
|
|
69
69
|
<shell>
|
70
|
-
|
71
|
-
|
70
|
+
gem install bundler
|
71
|
+
bundle install --without db
|
72
72
|
</shell>
|
73
73
|
|
74
|
-
|
74
|
+
The second command will install all dependencies, except MySQL and PostgreSQL. We will come back at these soon. With dependencies installed, you can run the whole Rails test suite with:
|
75
75
|
|
76
|
-
|
76
|
+
<shell>
|
77
|
+
rake test
|
78
|
+
</shell>
|
77
79
|
|
78
|
-
|
80
|
+
You can also run tests for an specific framework, like Action Pack, by going into its directory and executing the same command:
|
79
81
|
|
80
82
|
<shell>
|
81
|
-
|
83
|
+
cd actionpack
|
84
|
+
rake test
|
82
85
|
</shell>
|
83
86
|
|
84
|
-
|
87
|
+
h4. Testing Active Record
|
88
|
+
|
89
|
+
By default, when you run Active Record tests, it will execute the test suite three times, one for each of the main databases: SQLite3, MySQL and PostgreSQL. If you are adding a feature that is not specific to the database, you can run the test suite (or just one file) for just one of them. Here is an example for SQLite3:
|
90
|
+
|
91
|
+
<shell>
|
92
|
+
cd activerecord
|
93
|
+
rake test_sqlite3
|
94
|
+
rake test_sqlite3 TEST=test/cases/validations_test.rb
|
95
|
+
</shell>
|
96
|
+
|
97
|
+
If you want to use another database, as MySQL, you need to create a user named +rails+ with privileges on the test databases.
|
85
98
|
|
86
99
|
<shell>
|
87
100
|
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.*
|
@@ -90,7 +103,13 @@ mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.*
|
|
90
103
|
to 'rails'@'localhost';
|
91
104
|
</shell>
|
92
105
|
|
93
|
-
|
106
|
+
Then ensure you run bundle install without the +--without db+ option:
|
107
|
+
|
108
|
+
<shell>
|
109
|
+
bundle install
|
110
|
+
</shell>
|
111
|
+
|
112
|
+
Finally, enter this from the +activerecord+ directory to create the test databases:
|
94
113
|
|
95
114
|
<shell>
|
96
115
|
rake mysql:build_databases
|
@@ -100,18 +119,26 @@ NOTE: Using the rake task to create the test databases ensures they have the cor
|
|
100
119
|
|
101
120
|
If you’re using another database, check the files under +activerecord/test/connections+ in the Rails source code for default connection information. You can edit these files if you _must_ on your machine to provide different credentials, but obviously you should not push any such changes back to Rails.
|
102
121
|
|
103
|
-
|
122
|
+
You can now run tests as you did for +sqlite3+:
|
104
123
|
|
105
124
|
<shell>
|
106
|
-
rake
|
107
|
-
rake test_sqlite3 TEST=test/cases/validations_test.rb
|
125
|
+
rake test_mysql
|
108
126
|
</shell>
|
109
127
|
|
110
|
-
You can
|
128
|
+
You can also +myqsl+ with +postgresql+, +jdbcmysql+, +jdbcsqlite3+ or +jdbcpostgresql+. Check out the file +activerecord/RUNNING_UNIT_TESTS+ for information on running more targeted database tests, or the file +ci/ci_build.rb+ to see the test suite that the Rails continuous integration server runs.
|
111
129
|
|
130
|
+
NOTE: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite 3. Subtle differences between the various Active Record database adapters have been behind the rejection of many patches that looked OK when tested only against MySQL.
|
112
131
|
|
132
|
+
h4. Older versions of Rails
|
113
133
|
|
114
|
-
|
134
|
+
If you want to work add a fix to older versions of Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to Rails 2.3 branch:
|
135
|
+
|
136
|
+
<shell>
|
137
|
+
git branch --track 2-3-stable origin/2-3-stable
|
138
|
+
git checkout 2-3-stable
|
139
|
+
</shell>
|
140
|
+
|
141
|
+
TIP: You may want to "put your git branch name in your shell prompt":http://github.com/guides/put-your-git-branch-name-in-your-shell-prompt to make it easier to remember which version of the code you're working with.
|
115
142
|
|
116
143
|
h3. Helping to Resolve Existing Issues
|
117
144
|
|
@@ -205,7 +205,7 @@ Upon form submission the value entered by the user will be stored in +params[:pe
|
|
205
205
|
|
206
206
|
WARNING: You must pass the name of an instance variable, i.e. +:person+ or +"person"+, not an actual instance of your model object.
|
207
207
|
|
208
|
-
Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the "Active Record Validations and Callbacks":./
|
208
|
+
Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the "Active Record Validations and Callbacks":./active_record_validations_callbacks.html#displaying-validation-errors-in-the-view guide.
|
209
209
|
|
210
210
|
h4. Binding a Form to an Object
|
211
211
|
|
@@ -1,21 +1,21 @@
|
|
1
|
-
h2. Creating and
|
1
|
+
h2. Creating and Customizing Rails Generators
|
2
2
|
|
3
3
|
Rails generators are an essential tool if you plan to improve your workflow and in this guide you will learn how to create and customize already existing generators.
|
4
4
|
|
5
5
|
In this guide you will:
|
6
6
|
|
7
|
-
* Learn how to see which generators are available in your application
|
8
|
-
* Create a generator using templates
|
9
|
-
* Learn how Rails searches for generators before invoking them
|
10
|
-
* Customize your scaffold by creating new generators
|
11
|
-
* Customize your scaffold by changing
|
12
|
-
* Learn how to use fallbacks to avoid overwriting a huge set of generators
|
7
|
+
* Learn how to see which generators are available in your application
|
8
|
+
* Create a generator using templates
|
9
|
+
* Learn how Rails searches for generators before invoking them
|
10
|
+
* Customize your scaffold by creating new generators
|
11
|
+
* Customize your scaffold by changing generator templates
|
12
|
+
* Learn how to use fallbacks to avoid overwriting a huge set of generators
|
13
13
|
|
14
14
|
endprologue.
|
15
15
|
|
16
16
|
NOTE: This guide is about Rails generators for versions >= 3.0. Rails generators from previous versions are not supported.
|
17
17
|
|
18
|
-
h3. First
|
18
|
+
h3. First Contact
|
19
19
|
|
20
20
|
When you create an application using the +rails+ command, you are in fact using a Rails generator. After that, you can get a list of all available generators by just invoking +rails generate+:
|
21
21
|
|
@@ -25,15 +25,15 @@ $ cd myapp
|
|
25
25
|
$ rails generate
|
26
26
|
</shell>
|
27
27
|
|
28
|
-
You will get a list of all generators that comes with Rails. If you need a detailed description
|
28
|
+
You will get a list of all generators that comes with Rails. If you need a detailed description of the helper generator, for example, you can simply do:
|
29
29
|
|
30
30
|
<shell>
|
31
31
|
$ rails generate helper --help
|
32
32
|
</shell>
|
33
33
|
|
34
|
-
h3. Creating
|
34
|
+
h3. Creating Your First Generator
|
35
35
|
|
36
|
-
Since Rails 3.0, generators are built on top of "Thor":http://github.com/wycats/thor. Thor
|
36
|
+
Since Rails 3.0, generators are built on top of "Thor":http://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+.
|
37
37
|
|
38
38
|
The first step is to create a file at +RAILS_APP/lib/generators/initializer_generator.rb+ with the following content:
|
39
39
|
|
@@ -45,7 +45,7 @@ class InitializerGenerator < Rails::Generators::Base
|
|
45
45
|
end
|
46
46
|
</ruby>
|
47
47
|
|
48
|
-
Our new generator is quite simple: it inherits from +Rails::Generators::Base+ and
|
48
|
+
Our new generator is quite simple: it inherits from +Rails::Generators::Base+ and has one method definition. Each public method in the generator is executed when a generator is invoked. 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.
|
49
49
|
|
50
50
|
To invoke our new generator, we just need to do:
|
51
51
|
|
@@ -59,7 +59,7 @@ Before we go on, let's see our brand new generator description:
|
|
59
59
|
$ rails generate initializer --help
|
60
60
|
</shell>
|
61
61
|
|
62
|
-
Rails usually
|
62
|
+
Rails is usually able to generate good descriptions if a generator is namespaced, as +ActiveRecord::Generators::ModelGenerator+, but not in this particular case. We can solve this problem in two ways. The first one is calling +desc+ inside our generator:
|
63
63
|
|
64
64
|
<ruby>
|
65
65
|
class InitializerGenerator < Rails::Generators::Base
|
@@ -70,9 +70,9 @@ class InitializerGenerator < Rails::Generators::Base
|
|
70
70
|
end
|
71
71
|
</ruby>
|
72
72
|
|
73
|
-
Now we can see the new description by invoking +--help+
|
73
|
+
Now we can see the new description by invoking +--help+ on the new generator. The second way to add a description is by creating a file named +USAGE+ in the same directory as our generator. We are going to do that in the next step.
|
74
74
|
|
75
|
-
h3. Creating
|
75
|
+
h3. Creating Generators with Generators
|
76
76
|
|
77
77
|
A faster way to create a generator is using the generator's generator:
|
78
78
|
|
@@ -84,7 +84,7 @@ $ rails generate generator initializer
|
|
84
84
|
create lib/generators/initializer/templates
|
85
85
|
</shell>
|
86
86
|
|
87
|
-
And it will create a new generator as
|
87
|
+
And it will create a new generator as follows:
|
88
88
|
|
89
89
|
<ruby>
|
90
90
|
class InitializerGenerator < Rails::Generators::NamedBase
|
@@ -92,7 +92,7 @@ class InitializerGenerator < Rails::Generators::NamedBase
|
|
92
92
|
end
|
93
93
|
</ruby>
|
94
94
|
|
95
|
-
|
95
|
+
First, notice that we are inheriting from +Rails::Generators::NamedBase+ instead of +Rails::Generators::Base+. This means that our generator expects as least one argument, which will be the name of the initializer.
|
96
96
|
|
97
97
|
We can see that by invoking the description of this new generator (don't forget to delete the old generator file):
|
98
98
|
|
@@ -127,13 +127,13 @@ And let's execute our generator:
|
|
127
127
|
$ rails generate initializer foo
|
128
128
|
</shell>
|
129
129
|
|
130
|
-
We can see that now a initializer named foo was created at +config/initializers/foo.rb+ with the contents of our template. That means that copy_file copied a file in our source root to the destination path we gave. The method +file_name+ is automatically created when we inherit from +Rails::Generators::NamedBase+.
|
130
|
+
We can see that now a initializer named foo was created at +config/initializers/foo.rb+ with the contents of our template. That means that +copy_file+ copied a file in our source root to the destination path we gave. The method +file_name+ is automatically created when we inherit from +Rails::Generators::NamedBase+.
|
131
131
|
|
132
|
-
h3. Generators
|
132
|
+
h3. Generators Lookup
|
133
133
|
|
134
|
-
|
134
|
+
Now that we've created our first generator, we need to briefly discuss generator lookup. The way Rails finds generators is exactly the same way Ruby find files, i.e. using +$LOAD_PATHS+.
|
135
135
|
|
136
|
-
For instance, when you say +rails
|
136
|
+
For instance, when you say +rails generate initializer foo+, Rails knows you want to invoke the initializer generator and then search for the following generators in the $LOAD_PATHS:
|
137
137
|
|
138
138
|
<shell>
|
139
139
|
rails/generators/initializer/initializer_generator.rb
|
@@ -144,7 +144,7 @@ generators/initializer_generator.rb
|
|
144
144
|
|
145
145
|
If none of them is found, it raises an error message.
|
146
146
|
|
147
|
-
h3. Customizing
|
147
|
+
h3. Customizing Your Workflow
|
148
148
|
|
149
149
|
Rails generators are flexible enough to let you customize your scaffold the way you want. In your +config/application.rb+ there is a section just for generators:
|
150
150
|
|
@@ -156,7 +156,7 @@ config.generators do |g|
|
|
156
156
|
end
|
157
157
|
</ruby>
|
158
158
|
|
159
|
-
Before we customize our workflow, let's first see
|
159
|
+
Before we customize our workflow, let's first see what our scaffold looks like:
|
160
160
|
|
161
161
|
<shell>
|
162
162
|
$ rails generate scaffold User name:string
|
@@ -186,7 +186,7 @@ $ rails generate scaffold User name:string
|
|
186
186
|
create public/stylesheets/scaffold.css
|
187
187
|
</shell>
|
188
188
|
|
189
|
-
Looking at this output,
|
189
|
+
Looking at this output, it's easy to understand how generators work on 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.
|
190
190
|
|
191
191
|
Our first customization on the workflow will be to stop generating stylesheets and test fixtures on scaffold. We can achieve that by changing our application to the following:
|
192
192
|
|
@@ -199,15 +199,15 @@ config.generators do |g|
|
|
199
199
|
end
|
200
200
|
</ruby>
|
201
201
|
|
202
|
-
If we generate another resource on scaffold, we can notice that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use +Datamapper+ and +
|
202
|
+
If we generate another resource on scaffold, we can notice that neither stylesheets nor fixtures are created anymore. If you want to customize it further, for example to use +Datamapper+ and +RSpec+ instead of +ActiveRecord+ and +TestUnit+, it's just a matter of adding their gems to your application and configuring your generators.
|
203
203
|
|
204
|
-
To
|
204
|
+
To demonstrate this, we are going to create a new helper generator that simply adds some instance variable readers. First, we create a generator:
|
205
205
|
|
206
206
|
<shell>
|
207
207
|
$ rails generate generator my_helper
|
208
208
|
</shell>
|
209
209
|
|
210
|
-
After that, we can delete both 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:
|
210
|
+
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:
|
211
211
|
|
212
212
|
<ruby>
|
213
213
|
class MyHelperGenerator < Rails::Generators::NamedBase
|
@@ -227,7 +227,7 @@ We can try out our new generator by creating a helper for users:
|
|
227
227
|
$ rails generate my_helper users
|
228
228
|
</shell>
|
229
229
|
|
230
|
-
And it will generate the following helper file in app/helpers
|
230
|
+
And it will generate the following helper file in +app/helpers+:
|
231
231
|
|
232
232
|
<ruby>
|
233
233
|
module UsersHelper
|
@@ -258,7 +258,7 @@ $ rails generate scaffold Post body:text
|
|
258
258
|
|
259
259
|
We can notice on the output that our new helper was invoked instead of the Rails default. However one thing is missing, which is tests for our new generator and to do that, we are going to reuse old helpers test generators.
|
260
260
|
|
261
|
-
Since Rails 3.0, this is easy to do due to the hooks concept. Our new helper does not need to be focused in one specific test framework, it can simply provide a hook and a test framework just
|
261
|
+
Since Rails 3.0, this is easy to do due to the hooks concept. Our new helper does not need to be focused in one specific test framework, it can simply provide a hook and a test framework just needs to implement this hook in order to be compatible.
|
262
262
|
|
263
263
|
To do that, we can change your generator to the following:
|
264
264
|
|
@@ -276,7 +276,7 @@ end
|
|
276
276
|
end
|
277
277
|
</ruby>
|
278
278
|
|
279
|
-
Now, when the helper generator is invoked and
|
279
|
+
Now, when the helper generator is invoked and TestUnit is configured as the test framework, it will try to invoke both +MyHelper::Generators::TestUnitGenerator+ and +TestUnit::Generators::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add:
|
280
280
|
|
281
281
|
<ruby>
|
282
282
|
# Search for :helper instead of :my_helper
|
@@ -285,11 +285,11 @@ Now, when the helper generator is invoked and let's say test unit is configured
|
|
285
285
|
|
286
286
|
And now you can re-run scaffold for another resource and see it generating tests as well!
|
287
287
|
|
288
|
-
h3. Customizing
|
288
|
+
h3. Customizing Your Workflow by Changing Generators Templates
|
289
289
|
|
290
290
|
In the step above, we simply wanted to add a line to the generated helper, without adding any extra functionality. There is a simpler way to do that, and it's by replacing the templates of already existing generators.
|
291
291
|
|
292
|
-
In Rails 3.0 and above, generators
|
292
|
+
In Rails 3.0 and above, generators don't just look in the source root for templates, they also search for templates in other paths. And one of them is inside +RAILS_APP/lib/templates+. Since we want to customize +Rails::Generators::HelperGenerator+, we can do that by simply making a template copy inside +RAILS_APP/lib/templates/rails/helper+ with the name +helper.rb+. So let's create that file with the following content:
|
293
293
|
|
294
294
|
<erb>
|
295
295
|
module <%= class_name %>Helper
|
@@ -310,9 +310,9 @@ end
|
|
310
310
|
|
311
311
|
If you generate another resource, you can see that we got exactly the same result! This is useful if you want to customize your scaffold templates and/or layout by just creating +edit.html.erb+, +index.html.erb+ and so on inside +RAILS_APP/lib/templates/erb/scaffold+.
|
312
312
|
|
313
|
-
h3. Adding
|
313
|
+
h3. Adding Generators Fallbacks
|
314
314
|
|
315
|
-
One last feature about generators which is quite useful for plugin generators is fallbacks. For example, imagine that you want to add a feature on top of TestUnit test framework, like "shoulda":http://github.com/thoughtbot/shoulda does. Since TestUnit already implements all generators required by Rails and shoulda just
|
315
|
+
One last feature about generators which is quite useful for plugin generators is fallbacks. For example, imagine that you want to add a feature on top of TestUnit test framework, like "shoulda":http://github.com/thoughtbot/shoulda does. Since TestUnit already implements all generators required by Rails and shoulda just wants to overwrite part of it, there is no need for shoulda to reimplement some generators again, it can simply tell Rails to use a +TestUnit+ generator if none was found under the +Shoulda+ namespace.
|
316
316
|
|
317
317
|
We can easily simulate this behavior by changing our +config/application.rb+ once again:
|
318
318
|
|
@@ -324,11 +324,11 @@ config.generators do |g|
|
|
324
324
|
g.stylesheets false
|
325
325
|
|
326
326
|
# Add a fallback!
|
327
|
-
g.fallbacks[:
|
327
|
+
g.fallbacks[:shoulda] = :test_unit
|
328
328
|
end
|
329
329
|
</ruby>
|
330
330
|
|
331
|
-
Now, if create a Comment scaffold, you will see that shoulda generators are being invoked, and at the end, they are just falling back to test unit generators:
|
331
|
+
Now, if you create a Comment scaffold, you will see that the shoulda generators are being invoked, and at the end, they are just falling back to test unit generators:
|
332
332
|
|
333
333
|
<shell>
|
334
334
|
$ rails generate scaffold Comment body:text
|
@@ -357,7 +357,7 @@ $ rails generate scaffold Comment body:text
|
|
357
357
|
create test/unit/helpers/comments_helper_test.rb
|
358
358
|
</shell>
|
359
359
|
|
360
|
-
|
360
|
+
Fallbacks allow your generators to have a single responsibility, increasing code reuse and reducing the amount of duplication.
|
361
361
|
|
362
362
|
h3. Changelog
|
363
363
|
|