railties 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +36 -49
- data/README.rdoc +2 -1
- data/guides/assets/stylesheets/fixes.css +16 -0
- data/guides/rails_guides.rb +2 -2
- data/guides/rails_guides/generator.rb +8 -3
- data/guides/rails_guides/textile_extensions.rb +4 -2
- data/guides/source/2_2_release_notes.textile +3 -3
- data/guides/source/2_3_release_notes.textile +2 -2
- data/guides/source/3_0_release_notes.textile +14 -14
- data/guides/source/action_controller_overview.textile +54 -79
- data/guides/source/action_mailer_basics.textile +39 -9
- data/guides/source/action_view_overview.textile +257 -211
- data/guides/source/active_record_basics.textile +1 -1
- data/guides/source/active_record_querying.textile +217 -27
- data/guides/source/active_record_validations_callbacks.textile +94 -25
- data/guides/source/active_support_core_extensions.textile +109 -77
- data/guides/source/ajax_on_rails.textile +15 -150
- data/guides/source/api_documentation_guidelines.textile +12 -12
- data/guides/source/association_basics.textile +74 -60
- data/guides/source/caching_with_rails.textile +59 -60
- data/guides/source/command_line.textile +46 -47
- data/guides/source/configuring.textile +55 -37
- data/guides/source/contribute.textile +7 -7
- data/guides/source/contributing_to_ruby_on_rails.textile +14 -23
- data/guides/source/credits.html.erb +3 -3
- data/guides/source/debugging_rails_applications.textile +59 -46
- data/guides/source/form_helpers.textile +76 -31
- data/guides/source/generators.textile +39 -40
- data/guides/source/getting_started.textile +73 -94
- data/guides/source/i18n.textile +64 -58
- data/guides/source/index.html.erb +3 -3
- data/guides/source/initialization.textile +634 -3284
- data/guides/source/layout.html.erb +6 -7
- data/guides/source/layouts_and_rendering.textile +59 -60
- data/guides/source/migrations.textile +63 -59
- data/guides/source/nested_model_forms.textile +2 -2
- data/guides/source/performance_testing.textile +16 -16
- data/guides/source/plugins.textile +236 -1280
- data/guides/source/rails_application_templates.textile +37 -29
- data/guides/source/rails_on_rack.textile +4 -9
- data/guides/source/routing.textile +96 -75
- data/guides/source/ruby_on_rails_guides_guidelines.textile +19 -12
- data/guides/source/security.textile +57 -30
- data/guides/source/testing.textile +26 -24
- data/guides/w3c_validator.rb +2 -2
- data/lib/rails.rb +1 -7
- data/lib/rails/application.rb +46 -76
- data/lib/rails/application/bootstrap.rb +6 -11
- data/lib/rails/application/configuration.rb +43 -40
- data/lib/rails/application/finisher.rb +16 -4
- data/lib/rails/application/railties.rb +6 -24
- data/lib/rails/application/routes_reloader.rb +45 -0
- data/lib/rails/backtrace_cleaner.rb +1 -1
- data/lib/rails/cli.rb +7 -5
- data/lib/rails/commands.rb +27 -2
- data/lib/rails/commands/application.rb +14 -1
- data/lib/rails/commands/benchmarker.rb +3 -1
- data/lib/rails/commands/dbconsole.rb +2 -2
- data/lib/rails/commands/destroy.rb +3 -1
- data/lib/rails/commands/generate.rb +3 -1
- data/lib/rails/commands/plugin.rb +2 -7
- data/lib/rails/commands/plugin_new.rb +10 -0
- data/lib/rails/commands/profiler.rb +3 -1
- data/lib/rails/commands/server.rb +4 -0
- data/lib/rails/configuration.rb +8 -81
- data/lib/rails/console/app.rb +2 -2
- data/lib/rails/engine.rb +460 -78
- data/lib/rails/engine/configuration.rb +46 -49
- data/lib/rails/engine/railties.rb +33 -0
- data/lib/rails/generators.rb +11 -5
- data/lib/rails/generators/actions.rb +2 -27
- data/lib/rails/generators/app_base.rb +216 -0
- data/lib/rails/generators/base.rb +3 -2
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb +1 -1
- data/lib/rails/generators/generated_attribute.rb +2 -1
- data/lib/rails/generators/migration.rb +6 -2
- data/lib/rails/generators/named_base.rb +79 -3
- data/lib/rails/generators/rails/app/app_generator.rb +44 -209
- data/lib/rails/generators/rails/app/templates/Gemfile +15 -31
- data/lib/rails/generators/rails/app/templates/README +2 -2
- data/lib/rails/generators/rails/app/templates/Rakefile +1 -1
- data/lib/rails/generators/rails/app/templates/{public → app/assets}/images/rails.png +0 -0
- data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +8 -0
- data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +5 -0
- data/lib/rails/generators/rails/app/templates/app/mailers/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +4 -4
- data/lib/rails/generators/rails/app/templates/config/application.rb +19 -3
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +4 -4
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +11 -6
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +3 -3
- 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 +1 -2
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +14 -11
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +12 -0
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
- data/lib/rails/generators/rails/app/templates/config/routes.rb +1 -1
- data/lib/rails/generators/rails/app/templates/db/{seeds.rb → seeds.rb.tt} +2 -2
- data/lib/rails/generators/rails/app/templates/public/index.html +10 -8
- data/lib/rails/generators/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/rails/generators/rails/app/templates/test/{test_helper.rb.tt → test_helper.rb} +0 -0
- data/lib/rails/generators/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/rails/generators/rails/assets/USAGE +20 -0
- data/lib/rails/generators/rails/assets/assets_generator.rb +39 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js +2 -0
- data/lib/rails/generators/rails/assets/templates/javascript.js.coffee +3 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css +4 -0
- data/lib/rails/generators/rails/assets/templates/stylesheet.css.scss +5 -0
- data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
- data/lib/rails/generators/rails/controller/templates/controller.rb +2 -0
- data/lib/rails/generators/rails/generator/generator_generator.rb +2 -2
- data/lib/rails/generators/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/rails/generators/rails/helper/templates/helper.rb +2 -0
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -0
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +4 -4
- data/lib/rails/generators/rails/plugin_new/USAGE +10 -0
- data/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +303 -0
- data/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec +9 -0
- data/lib/rails/generators/rails/plugin_new/templates/Gemfile +11 -0
- data/lib/rails/generators/rails/plugin_new/templates/MIT-LICENSE +20 -0
- data/lib/rails/generators/rails/plugin_new/templates/README.rdoc +3 -0
- data/lib/rails/generators/rails/plugin_new/templates/Rakefile +21 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/controllers/%name%/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/helpers/%name%/application_helper.rb.tt +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/app/models/.empty_directory +0 -0
- data/lib/rails/generators/rails/plugin_new/templates/config/routes.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/gitignore +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%.rb +6 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/%name%/engine.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/lib/tasks/%name%_tasks.rake +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/application.rb +16 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb +10 -0
- data/lib/rails/generators/rails/plugin_new/templates/rails/routes.rb +4 -0
- data/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +5 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/%name%_test.rb +7 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/integration/navigation_test.rb +12 -0
- data/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb +10 -0
- data/lib/rails/generators/rails/resource/resource_generator.rb +2 -2
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +20 -1
- data/lib/rails/generators/rails/{stylesheets → scaffold}/templates/scaffold.css +0 -0
- data/lib/rails/generators/rails/scaffold/templates/scaffold.css.scss +58 -0
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +21 -19
- data/lib/rails/generators/resource_helpers.rb +3 -3
- data/lib/rails/generators/test_case.rb +2 -20
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/helper/templates/helper_test.rb +2 -0
- data/lib/rails/generators/test_unit/integration/templates/integration_test.rb +3 -4
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +5 -4
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml +1 -1
- data/lib/rails/generators/test_unit/model/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/observer/templates/unit_test.rb +5 -4
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +3 -4
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +7 -5
- data/lib/rails/info.rb +0 -1
- data/lib/rails/paths.rb +119 -65
- data/lib/rails/plugin.rb +18 -19
- data/lib/rails/rack/log_tailer.rb +1 -1
- data/lib/rails/railtie.rb +50 -47
- data/lib/rails/railtie/configurable.rb +20 -10
- data/lib/rails/railtie/configuration.rb +20 -19
- data/lib/rails/source_annotation_extractor.rb +5 -5
- data/lib/rails/tasks.rb +1 -0
- data/lib/rails/tasks/assets.rake +10 -0
- data/lib/rails/tasks/documentation.rake +2 -8
- data/lib/rails/tasks/engine.rake +69 -0
- data/lib/rails/tasks/framework.rake +4 -21
- data/lib/rails/tasks/misc.rake +1 -1
- data/lib/rails/tasks/routes.rake +2 -1
- data/lib/rails/test_help.rb +17 -1
- data/lib/rails/test_unit/railtie.rb +1 -1
- data/lib/rails/test_unit/testing.rake +8 -3
- data/lib/rails/version.rb +3 -3
- metadata +128 -100
- checksums.yaml +0 -7
- data/lib/rails/application/configurable.rb +0 -19
- data/lib/rails/console/sandbox.rb +0 -6
- data/lib/rails/deprecation.rb +0 -41
- data/lib/rails/engine/configurable.rb +0 -25
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +0 -62
- data/lib/rails/generators/rails/app/templates/public/javascripts/application.js +0 -2
- data/lib/rails/generators/rails/app/templates/public/javascripts/controls.js +0 -965
- data/lib/rails/generators/rails/app/templates/public/javascripts/dragdrop.js +0 -974
- data/lib/rails/generators/rails/app/templates/public/javascripts/effects.js +0 -1123
- data/lib/rails/generators/rails/app/templates/public/javascripts/prototype.js +0 -6001
- data/lib/rails/generators/rails/app/templates/public/javascripts/rails.js +0 -202
- data/lib/rails/generators/rails/stylesheets/USAGE +0 -5
- data/lib/rails/generators/rails/stylesheets/stylesheets_generator.rb +0 -9
- data/lib/rails/info_routes.rb +0 -3
@@ -9,6 +9,7 @@ In this guide you will:
|
|
9
9
|
* Generate select boxes from multiple types of data
|
10
10
|
* Understand the date and time helpers Rails provides
|
11
11
|
* Learn what makes a file upload form different
|
12
|
+
* Learn some cases of building forms to external resources
|
12
13
|
* Find out where to look for complex forms
|
13
14
|
|
14
15
|
endprologue.
|
@@ -31,17 +32,18 @@ When called without arguments like this, it creates a form element that has the
|
|
31
32
|
Sample output from +form_tag+:
|
32
33
|
|
33
34
|
<html>
|
34
|
-
<form action="/home/index" method="post">
|
35
|
+
<form accept-charset="UTF-8" action="/home/index" method="post">
|
35
36
|
<div style="margin:0;padding:0">
|
37
|
+
<input name="utf8" type="hidden" value="✓" />
|
36
38
|
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
|
37
39
|
</div>
|
38
40
|
Form contents
|
39
41
|
</form>
|
40
42
|
</html>
|
41
43
|
|
42
|
-
If you carefully observe this output, you can see that the helper generated something you didn't specify: a +div+ element with
|
44
|
+
If you carefully observe this output, you can see that the helper generated something you didn't specify: a +div+ element with two hidden input elements inside. The first input element with name +utf8+ enforces browsers to properly respect your form's character encoding and is generated for all forms whether action is "get" or "post". Second input element with name +authenticity_token+ is a security feature of Rails called *cross-site request forgery protection* and form helpers generate it for every form whose action is not "get" (provided that this security feature is enabled). You can read more about this in the "Ruby On Rails Security Guide":./security.html#_cross_site_reference_forgery_csrf.
|
43
45
|
|
44
|
-
NOTE: Throughout this guide, this +div+ with the hidden input will be stripped away to have clearer code samples.
|
46
|
+
NOTE: Throughout this guide, this +div+ with the hidden input elements will be stripped away to have clearer code samples.
|
45
47
|
|
46
48
|
h4. A Generic Search Form
|
47
49
|
|
@@ -66,12 +68,12 @@ A basic search form
|
|
66
68
|
<% end %>
|
67
69
|
</erb>
|
68
70
|
|
69
|
-
TIP: +search_path+ can be a named route specified in "routes.rb": <br /><
|
71
|
+
TIP: +search_path+ can be a named route specified in "routes.rb" as: <br /><code>match "search" => "search"</code> This declares that path "/search" will be handled by action "search" belonging to controller "search".
|
70
72
|
|
71
73
|
The above view code will result in the following markup:
|
72
74
|
|
73
75
|
<html>
|
74
|
-
<form action="/search" method="get">
|
76
|
+
<form accept-charset="UTF-8" action="/search" method="get">
|
75
77
|
<label for="q">Search for:</label>
|
76
78
|
<input id="q" name="q" type="text" />
|
77
79
|
<input name="commit" type="submit" value="Search" />
|
@@ -90,14 +92,14 @@ As with the +link_to+ helper, the path argument doesn't have to be given a strin
|
|
90
92
|
|
91
93
|
<ruby>
|
92
94
|
form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form")
|
93
|
-
# => <form action="/people/search?method=get&class=nifty_form" method="post">
|
95
|
+
# => <form accept-charset="UTF-8" action="/people/search?method=get&class=nifty_form" method="post">
|
94
96
|
</ruby>
|
95
97
|
|
96
98
|
Here you wanted to pass two hashes, but the Ruby interpreter sees only one hash, so Rails will construct a URL with extraneous parameters. The correct way of passing multiple hashes as arguments is to delimit the first hash (or both hashes) with curly brackets:
|
97
99
|
|
98
100
|
<ruby>
|
99
101
|
form_tag({:controller => "people", :action => "search"}, :method => "get", :class => "nifty_form")
|
100
|
-
# => <form action="/people/search" method="get" class="nifty_form">
|
102
|
+
# => <form accept-charset="UTF-8" action="/people/search" method="get" class="nifty_form">
|
101
103
|
</ruby>
|
102
104
|
|
103
105
|
This is a common pitfall when using form helpers, since many of them accept multiple hashes. So in future, if a helper produces unexpected output, make sure that you have delimited the hash parameters properly.
|
@@ -106,7 +108,7 @@ WARNING: Do not delimit the second hash without doing so with the first hash, ot
|
|
106
108
|
|
107
109
|
h4. Helpers for Generating Form Elements
|
108
110
|
|
109
|
-
Rails provides a series of helpers for generating form elements such as checkboxes, text fields
|
111
|
+
Rails provides a series of helpers for generating form elements such as checkboxes, text fields and radio buttons. These basic helpers, with names ending in <notextile>_tag</notextile> such as +text_field_tag+ and +check_box_tag+ generate just a single +<input>+ element. The first parameter to these is always the name of the input. In the controller this name will be the key in the +params+ hash used to get the value entered by the user. For example, if the form contains
|
110
112
|
|
111
113
|
<erb>
|
112
114
|
<%= text_field_tag(:query) %>
|
@@ -186,7 +188,7 @@ output:
|
|
186
188
|
|
187
189
|
Hidden inputs are not shown to the user, but they hold data like any textual input. Values inside them can be changed with JavaScript.
|
188
190
|
|
189
|
-
TIP: If you're using password input fields (for any purpose), you might want to
|
191
|
+
TIP: If you're using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged.
|
190
192
|
|
191
193
|
|
192
194
|
h3. Dealing with Model Objects
|
@@ -228,16 +230,16 @@ end
|
|
228
230
|
The corresponding view +app/views/articles/new.html.erb+ using +form_for+ looks like this:
|
229
231
|
|
230
232
|
<erb>
|
231
|
-
<%= form_for
|
233
|
+
<%= form_for @article, :url => { :action => "create" }, :html => {:class => "nifty_form"} do |f| %>
|
232
234
|
<%= f.text_field :title %>
|
233
235
|
<%= f.text_area :body, :size => "60x12" %>
|
234
|
-
<%=
|
236
|
+
<%= f.submit "Create" %>
|
235
237
|
<% end %>
|
236
238
|
</erb>
|
237
239
|
|
238
240
|
There are a few things to note here:
|
239
241
|
|
240
|
-
#
|
242
|
+
# +@article+ is the actual object being edited.
|
241
243
|
# There is a single hash of options. Routing options are passed in the +:url+ hash, HTML options are passed in the +:html+ hash.
|
242
244
|
# The +form_for+ method yields a *form builder* object (the +f+ variable).
|
243
245
|
# Methods to create form controls are called *on* the form builder object +f+
|
@@ -245,7 +247,7 @@ There are a few things to note here:
|
|
245
247
|
The resulting HTML is:
|
246
248
|
|
247
249
|
<html>
|
248
|
-
<form action="/articles/create" method="post" class="nifty_form">
|
250
|
+
<form accept-charset="UTF-8" action="/articles/create" method="post" class="nifty_form">
|
249
251
|
<input id="article_title" name="article[title]" size="30" type="text" />
|
250
252
|
<textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
|
251
253
|
<input name="commit" type="submit" value="Create" />
|
@@ -256,10 +258,10 @@ The name passed to +form_for+ controls the key used in +params+ to access the fo
|
|
256
258
|
|
257
259
|
The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder.
|
258
260
|
|
259
|
-
You can create a similar binding without actually creating
|
261
|
+
You can create a similar binding without actually creating +<form>+ tags with the +fields_for+ helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for creating both like so:
|
260
262
|
|
261
263
|
<erb>
|
262
|
-
<%= form_for
|
264
|
+
<%= form_for @person, :url => { :action => "create" } do |person_form| %>
|
263
265
|
<%= person_form.text_field :name %>
|
264
266
|
<%= fields_for @person.contact_detail do |contact_details_form| %>
|
265
267
|
<%= contact_details_form.text_field :phone_number %>
|
@@ -270,7 +272,7 @@ You can create a similar binding without actually creating +<form>+ tags
|
|
270
272
|
which produces the following output:
|
271
273
|
|
272
274
|
<html>
|
273
|
-
<form action="/people/create" class="new_person" id="new_person" method="post">
|
275
|
+
<form accept-charset="UTF-8" action="/people/create" class="new_person" id="new_person" method="post">
|
274
276
|
<input id="person_name" name="person[name]" size="30" type="text" />
|
275
277
|
<input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" />
|
276
278
|
</form>
|
@@ -293,13 +295,13 @@ When dealing with RESTful resources, calls to +form_for+ can get significantly e
|
|
293
295
|
<ruby>
|
294
296
|
## Creating a new article
|
295
297
|
# long-style:
|
296
|
-
form_for(
|
298
|
+
form_for(@article, :url => articles_path)
|
297
299
|
# same thing, short-style (record identification gets used):
|
298
300
|
form_for(@article)
|
299
301
|
|
300
302
|
## Editing an existing article
|
301
303
|
# long-style:
|
302
|
-
form_for(
|
304
|
+
form_for(@article, :url => article_path(@article), :html => { :method => "put" })
|
303
305
|
# short-style:
|
304
306
|
form_for(@article)
|
305
307
|
</ruby>
|
@@ -340,9 +342,10 @@ form_tag(search_path, :method => "put")
|
|
340
342
|
output:
|
341
343
|
|
342
344
|
<html>
|
343
|
-
<form action="/search" method="post">
|
345
|
+
<form accept-charset="UTF-8" action="/search" method="post">
|
344
346
|
<div style="margin:0;padding:0">
|
345
347
|
<input name="_method" type="hidden" value="put" />
|
348
|
+
<input name="utf8" type="hidden" value="✓" />
|
346
349
|
<input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
|
347
350
|
</div>
|
348
351
|
...
|
@@ -435,7 +438,7 @@ As with other helpers, if you were to use the +select+ helper on a form builder
|
|
435
438
|
<%= f.select(:city_id, ...) %>
|
436
439
|
</erb>
|
437
440
|
|
438
|
-
WARNING: If you are using +select+ (or similar helpers such as +collection_select+, +select_tag+) to set a +belongs_to+ association you must pass the name of the foreign key (in the example above +city_id+), not the name of association itself.
|
441
|
+
WARNING: If you are using +select+ (or similar helpers such as +collection_select+, +select_tag+) to set a +belongs_to+ association you must pass the name of the foreign key (in the example above +city_id+), not the name of association itself. If you specify +city+ instead of +city_id+ Active Record will raise an error along the lines of <tt> ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) </tt> when you pass the +params+ hash to +Person.new+ or +update_attributes+. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential security ramifications of allowing users to edit foreign keys directly. You may wish to consider the use of +attr_protected+ and +attr_accessible+. For further details on this, see the "Ruby On Rails Security Guide":security.html#_mass_assignment.
|
439
442
|
|
440
443
|
h4. Option Tags from a Collection of Arbitrary Objects
|
441
444
|
|
@@ -472,7 +475,7 @@ To leverage time zone support in Rails, you have to ask your users what time zon
|
|
472
475
|
|
473
476
|
There is also +time_zone_options_for_select+ helper for a more manual (therefore more customizable) way of doing this. Read the API documentation to learn about the possible arguments for these two methods.
|
474
477
|
|
475
|
-
Rails _used_ to have a +country_select+ helper for choosing countries, but this has been extracted to the "country_select plugin":
|
478
|
+
Rails _used_ to have a +country_select+ helper for choosing countries, but this has been extracted to the "country_select plugin":https://github.com/chrislerum/country_select. When using this, be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from Rails).
|
476
479
|
|
477
480
|
h3. Using Date and Time Form Helpers
|
478
481
|
|
@@ -510,7 +513,7 @@ The +:prefix+ option is the key used to retrieve the hash of date components fro
|
|
510
513
|
h4(#select-model-object-helpers). Model Object Helpers
|
511
514
|
|
512
515
|
+select_date+ does not work well with forms that update or create Active Record objects as Active Record expects each element of the +params+ hash to correspond to one attribute.
|
513
|
-
The model object helpers for dates and times submit parameters with special names,
|
516
|
+
The model object helpers for dates and times submit parameters with special names, when Active Record sees parameters with such names it knows they must be combined with the other parameters and given to a constructor appropriate to the column type. For example:
|
514
517
|
|
515
518
|
<erb>
|
516
519
|
<%= date_select :person, :birth_date %>
|
@@ -555,7 +558,7 @@ will produce the same output if the current year is 2009 and the value chosen by
|
|
555
558
|
|
556
559
|
h3. Uploading Files
|
557
560
|
|
558
|
-
A common task is uploading some sort of file, whether it's a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the form's encoding *MUST* be set to "multipart/form-data". If you
|
561
|
+
A common task is uploading some sort of file, whether it's a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the rendered form's encoding *MUST* be set to "multipart/form-data". If you use +form_for+, this is done automatically. If you use +form_tag+, you must set it yourself, as per the following example.
|
559
562
|
|
560
563
|
The following two forms both upload a file.
|
561
564
|
|
@@ -564,11 +567,13 @@ The following two forms both upload a file.
|
|
564
567
|
<%= file_field_tag 'picture' %>
|
565
568
|
<% end %>
|
566
569
|
|
567
|
-
<%= form_for @person
|
570
|
+
<%= form_for @person do |f| %>
|
568
571
|
<%= f.file_field :picture %>
|
569
572
|
<% end %>
|
570
573
|
</erb>
|
571
574
|
|
575
|
+
NOTE: Since Rails 3.1, forms rendered using +form_for+ have their encoding set to <tt>multipart/form-data</tt> automatically once a +file_field+ is used inside the block. Previous versions required you to set this explicitly.
|
576
|
+
|
572
577
|
Rails provides the usual pair of helpers: the barebones +file_field_tag+ and the model oriented +file_field+. The only difference with other helpers is that you cannot set a default value for file inputs as this would have no meaning. As you would expect in the first case the uploaded file is in +params[:picture]+ and in the second case in +params[:person][:picture]+.
|
573
578
|
|
574
579
|
h4. What Gets Uploaded
|
@@ -584,13 +589,13 @@ def upload
|
|
584
589
|
end
|
585
590
|
</ruby>
|
586
591
|
|
587
|
-
Once a file has been uploaded, there are a multitude of potential tasks, ranging from where to store the files (on disk, Amazon S3, etc) and associating them with models to resizing image files and generating thumbnails. The intricacies of this are beyond the scope of this guide, but there are several plugins designed to assist with these. Two of the better known ones are "Attachment-Fu":
|
592
|
+
Once a file has been uploaded, there are a multitude of potential tasks, ranging from where to store the files (on disk, Amazon S3, etc) and associating them with models to resizing image files and generating thumbnails. The intricacies of this are beyond the scope of this guide, but there are several plugins designed to assist with these. Two of the better known ones are "Attachment-Fu":https://github.com/technoweenie/attachment_fu and "Paperclip":http://www.thoughtbot.com/projects/paperclip.
|
588
593
|
|
589
594
|
NOTE: If the user has not selected a file the corresponding parameter will be an empty string.
|
590
595
|
|
591
596
|
h4. Dealing with Ajax
|
592
597
|
|
593
|
-
Unlike other forms making an asynchronous file upload form is not as simple as
|
598
|
+
Unlike other forms making an asynchronous file upload form is not as simple as providing +form_for+ with <tt>:remote => true</tt>. With an Ajax form the serialization is done by JavaScript running inside the browser and since JavaScript cannot read files from your hard drive the file cannot be uploaded. The most common workaround is to use an invisible iframe that serves as the target for the form submission.
|
594
599
|
|
595
600
|
h3. Customizing Form Builders
|
596
601
|
|
@@ -637,7 +642,12 @@ action for a Person model, +params[:model]+ would usually be a hash of all the a
|
|
637
642
|
|
638
643
|
Fundamentally HTML forms don't know about any sort of structured data, all they generate is name–value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses.
|
639
644
|
|
640
|
-
TIP: You may find you can try out examples in this section faster by using the console to directly invoke Rails' parameter parser. For example
|
645
|
+
TIP: You may find you can try out examples in this section faster by using the console to directly invoke Rails' parameter parser. For example,
|
646
|
+
|
647
|
+
<ruby>
|
648
|
+
ActionController::UrlEncodedPairParser.parse_query_parameters "name=fred&phone=0123456789"
|
649
|
+
# => {"name"=>"fred", "phone"=>"0123456789"}
|
650
|
+
</ruby>
|
641
651
|
|
642
652
|
h4. Basic Structures
|
643
653
|
|
@@ -713,7 +723,7 @@ You might want to render a form with a set of edit fields for each of a person's
|
|
713
723
|
Assuming the person had two addresses, with ids 23 and 45 this would create output similar to this:
|
714
724
|
|
715
725
|
<html>
|
716
|
-
<form action="/people/1" class="edit_person" id="edit_person_1" method="post">
|
726
|
+
<form accept-charset="UTF-8" action="/people/1" class="edit_person" id="edit_person_1" method="post">
|
717
727
|
<input id="person_name" name="person[name]" size="30" type="text" />
|
718
728
|
<input id="person_address_23_city" name="person[address][23][city]" size="30" type="text" />
|
719
729
|
<input id="person_address_45_city" name="person[address][45][city]" size="30" type="text" />
|
@@ -754,6 +764,40 @@ As a shortcut you can append [] to the name and omit the +:index+ option. This i
|
|
754
764
|
|
755
765
|
produces exactly the same output as the previous example.
|
756
766
|
|
767
|
+
h3. Forms to external resources
|
768
|
+
|
769
|
+
If you need to post some data to an external resource it is still great to build your from using rails form helpers. But sometimes you need to set an +authenticity_token+ for this resource. You can do it by passing an +:authenticity_token => 'your_external_token'+ parameter to the +form_tag+ options:
|
770
|
+
|
771
|
+
<erb>
|
772
|
+
<%= form_tag 'http://farfar.away/form', :authenticity_token => 'external_token') do %>
|
773
|
+
Form contents
|
774
|
+
<% end %>
|
775
|
+
</erb>
|
776
|
+
|
777
|
+
Sometimes when you submit data to an external resource, like payment gateway, fields you can use in your form are limited by an external API. So you may want not to generate an +authenticity_token+ hidden field at all. For doing this just pass +false+ to the +:authenticity_token+ option:
|
778
|
+
|
779
|
+
<erb>
|
780
|
+
<%= form_tag 'http://farfar.away/form', :authenticity_token => 'external_token') do %>
|
781
|
+
Form contents
|
782
|
+
<% end %>
|
783
|
+
</erb>
|
784
|
+
|
785
|
+
The same technique is available for the +form_for+ too:
|
786
|
+
|
787
|
+
<erb>
|
788
|
+
<%= form_for @invoice, :url => external_url, :authenticity_token => 'external_token' do |f|
|
789
|
+
Form contents
|
790
|
+
<% end %>
|
791
|
+
</erb>
|
792
|
+
|
793
|
+
Or if you don't want to render an +authenticity_token+ field:
|
794
|
+
|
795
|
+
<erb>
|
796
|
+
<%= form_for @invoice, :url => external_url, :authenticity_token => false do |f|
|
797
|
+
Form contents
|
798
|
+
<% end %>
|
799
|
+
</erb>
|
800
|
+
|
757
801
|
h3. Building Complex Forms
|
758
802
|
|
759
803
|
Many apps grow beyond simple forms editing a single object. For example when creating a Person you might want to allow the user to (on the same form) create multiple address records (home, work, etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. While this guide has shown you all the pieces necessary to handle this, Rails does not yet have a standard end-to-end way of accomplishing this, but many have come up with viable approaches. These include:
|
@@ -761,12 +805,13 @@ Many apps grow beyond simple forms editing a single object. For example when cre
|
|
761
805
|
* As of Rails 2.3, Rails includes "Nested Attributes":./2_3_release_notes.html#nested-attributes and "Nested Object Forms":./2_3_release_notes.html#nested-object-forms
|
762
806
|
* Ryan Bates' series of Railscasts on "complex forms":http://railscasts.com/episodes/75
|
763
807
|
* Handle Multiple Models in One Form from "Advanced Rails Recipes":http://media.pragprog.com/titles/fr_arr/multiple_models_one_form.pdf
|
764
|
-
* Eloy Duran's "complex-forms-examples":
|
765
|
-
* Lance Ivy's "nested_assignment":
|
766
|
-
* James Golick's "attribute_fu":
|
808
|
+
* Eloy Duran's "complex-forms-examples":https://github.com/alloy/complex-form-examples/ application
|
809
|
+
* Lance Ivy's "nested_assignment":https://github.com/cainlevy/nested_assignment/tree/master plugin and "sample application":https://github.com/cainlevy/complex-form-examples/tree/cainlevy
|
810
|
+
* James Golick's "attribute_fu":https://github.com/jamesgolick/attribute_fu plugin
|
767
811
|
|
768
812
|
h3. Changelog
|
769
813
|
|
814
|
+
* February 5, 2011: Added 'Forms to external resources' section. Timothy N. Tsvetkov <timothy.tsvetkov@gmail.com>
|
770
815
|
* April 6, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
|
771
816
|
|
772
817
|
h3. Authors
|
@@ -34,7 +34,7 @@ $ rails generate helper --help
|
|
34
34
|
|
35
35
|
h3. Creating Your First Generator
|
36
36
|
|
37
|
-
Since Rails 3.0, generators are built on top of "Thor":
|
37
|
+
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+.
|
38
38
|
|
39
39
|
The first step is to create a file at +lib/generators/initializer_generator.rb+ with the following content:
|
40
40
|
|
@@ -149,7 +149,7 @@ generators/initializer_generator.rb
|
|
149
149
|
|
150
150
|
If none is found you get an error message.
|
151
151
|
|
152
|
-
INFO: The examples above put files under the application's +lib+ because said
|
152
|
+
INFO: The examples above put files under the application's +lib+ because said directory belongs to +$LOAD_PATH+.
|
153
153
|
|
154
154
|
h3. Customizing Your Workflow
|
155
155
|
|
@@ -190,7 +190,7 @@ $ rails generate scaffold User name:string
|
|
190
190
|
invoke test_unit
|
191
191
|
create test/unit/helpers/users_helper_test.rb
|
192
192
|
invoke stylesheets
|
193
|
-
create
|
193
|
+
create app/assets/stylesheets/scaffold.css
|
194
194
|
</shell>
|
195
195
|
|
196
196
|
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.
|
@@ -319,7 +319,7 @@ If you generate another resource, you can see that we get exactly the same resul
|
|
319
319
|
|
320
320
|
h3. Adding Generators Fallbacks
|
321
321
|
|
322
|
-
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 like "shoulda":
|
322
|
+
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 like "shoulda":https://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.
|
323
323
|
|
324
324
|
We can easily simulate this behavior by changing our +config/application.rb+ once again:
|
325
325
|
|
@@ -345,7 +345,7 @@ $ rails generate scaffold Comment body:text
|
|
345
345
|
invoke shoulda
|
346
346
|
create test/unit/comment_test.rb
|
347
347
|
create test/fixtures/comments.yml
|
348
|
-
route
|
348
|
+
route resources :comments
|
349
349
|
invoke scaffold_controller
|
350
350
|
create app/controllers/comments_controller.rb
|
351
351
|
invoke erb
|
@@ -371,24 +371,24 @@ h3. Application templates
|
|
371
371
|
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".
|
372
372
|
|
373
373
|
<ruby>
|
374
|
-
|
375
|
-
|
374
|
+
gem("rspec-rails", :group => "test")
|
375
|
+
gem("cucumber-rails", :group => "test")
|
376
376
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
377
|
+
if yes?("Would you like to install Devise?")
|
378
|
+
gem("devise")
|
379
|
+
generate("devise:install")
|
380
|
+
model_name = ask("What would you like the user model to be called? [user]")
|
381
|
+
model_name = "user" if model_name.blank?
|
382
|
+
generate("devise", model_name)
|
383
|
+
end
|
384
384
|
</ruby>
|
385
385
|
|
386
|
-
In the above template we specify that the application relies on the +rspec-rails+ and +cucumber-rails+ gem so these two will be added to the +test+ group in the +Gemfile+. Then we pose a question to the user about whether or not they would like to install Devise. If the user replies "y" or "yes" to this question, then the template will add Devise to the +Gemfile+ outside of any group and then runs the +devise:install+ generator. This template then takes the users input and runs the
|
386
|
+
In the above template we specify that the application relies on the +rspec-rails+ and +cucumber-rails+ gem so these two will be added to the +test+ group in the +Gemfile+. Then we pose a question to the user about whether or not they would like to install Devise. If the user replies "y" or "yes" to this question, then the template will add Devise to the +Gemfile+ outside of any group and then runs the +devise:install+ generator. This template then takes the users input and runs the +devise+ generator, with the user's answer from the last question being passed to this generator.
|
387
387
|
|
388
388
|
Imagine that this template was in a file called +template.rb+. We can use it to modify the outcome of the +rails new+ command by using the +-m+ option and passing in the filename:
|
389
389
|
|
390
390
|
<shell>
|
391
|
-
|
391
|
+
$ rails new thud -m template.rb
|
392
392
|
</shell>
|
393
393
|
|
394
394
|
This command will generate the +Thud+ application, and then apply the template to the generated output.
|
@@ -396,14 +396,14 @@ This command will generate the +Thud+ application, and then apply the template t
|
|
396
396
|
Templates don't have to be stored on the local system, the +-m+ option also supports online templates:
|
397
397
|
|
398
398
|
<shell>
|
399
|
-
|
399
|
+
$ rails new thud -m https://gist.github.com/722911.txt
|
400
400
|
</shell>
|
401
401
|
|
402
402
|
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.
|
403
403
|
|
404
404
|
h3. Generator methods
|
405
405
|
|
406
|
-
The following are methods available for both generators and templates for Rails.
|
406
|
+
The following are methods available for both generators and templates for Rails.
|
407
407
|
|
408
408
|
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
|
409
409
|
|
@@ -428,8 +428,8 @@ h4. +gem+
|
|
428
428
|
Specifies a gem dependency of the application.
|
429
429
|
|
430
430
|
<ruby>
|
431
|
-
|
432
|
-
|
431
|
+
gem("rspec", :group => "test", :version => "2.1.0")
|
432
|
+
gem("devise", "1.1.5")
|
433
433
|
</ruby>
|
434
434
|
|
435
435
|
Available options are:
|
@@ -470,10 +470,9 @@ Adds a line to +config/application.rb+ directly after the application class defi
|
|
470
470
|
This method can also take a block:
|
471
471
|
|
472
472
|
<ruby>
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
end
|
473
|
+
application do
|
474
|
+
"config.asset_host = 'http://example.com'"
|
475
|
+
end
|
477
476
|
</ruby>
|
478
477
|
|
479
478
|
Available options are:
|
@@ -481,9 +480,9 @@ Available options are:
|
|
481
480
|
* +: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:
|
482
481
|
|
483
482
|
<ruby>
|
484
|
-
|
485
|
-
|
486
|
-
|
483
|
+
application(nil, :env => "development") do
|
484
|
+
"config.asset_host = 'http://localhost:3000'"
|
485
|
+
end
|
487
486
|
</ruby>
|
488
487
|
|
489
488
|
h4. +git+
|
@@ -526,9 +525,9 @@ Places a file into +lib+ which contains the specified code.
|
|
526
525
|
This method also takes a block:
|
527
526
|
|
528
527
|
<ruby>
|
529
|
-
|
530
|
-
|
531
|
-
|
528
|
+
lib("super_special.rb") do
|
529
|
+
puts "Super special!"
|
530
|
+
end
|
532
531
|
</ruby>
|
533
532
|
|
534
533
|
h4. +rakefile+
|
@@ -542,13 +541,13 @@ Creates a Rake file in the +lib/tasks+ directory of the application.
|
|
542
541
|
This method also takes a block:
|
543
542
|
|
544
543
|
<ruby>
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
544
|
+
rakefile("test.rake") do
|
545
|
+
%Q{
|
546
|
+
task :rock => :environment do
|
547
|
+
puts "Rockin'"
|
548
|
+
end
|
549
|
+
}
|
550
|
+
end
|
552
551
|
</ruby>
|
553
552
|
|
554
553
|
h4. +initializer+
|
@@ -562,9 +561,9 @@ Creates an initializer in the +config/initializers+ directory of the application
|
|
562
561
|
This method also takes a block:
|
563
562
|
|
564
563
|
<ruby>
|
565
|
-
|
566
|
-
|
567
|
-
|
564
|
+
initializer("begin.rb") do
|
565
|
+
puts "Almost done!"
|
566
|
+
end
|
568
567
|
</ruby>
|
569
568
|
|
570
569
|
h4. +generate+
|