railties 3.0.0.beta → 3.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +15 -1
- data/README +9 -9
- data/bin/rails +28 -9
- data/guides/images/challenge.png +0 -0
- data/guides/images/edge_badge.png +0 -0
- data/guides/images/posts_index.png +0 -0
- data/guides/images/rails_welcome.png +0 -0
- data/guides/rails_guides.rb +9 -22
- data/guides/rails_guides/generator.rb +79 -50
- data/guides/rails_guides/textile_extensions.rb +3 -3
- data/guides/source/2_2_release_notes.textile +1 -1
- data/guides/source/2_3_release_notes.textile +1 -1
- data/guides/source/3_0_release_notes.textile +46 -38
- data/guides/source/action_controller_overview.textile +2 -2
- data/guides/source/action_mailer_basics.textile +4 -4
- data/guides/source/action_view_overview.textile +2 -2
- data/guides/source/active_record_querying.textile +73 -95
- data/guides/source/active_support_core_extensions.textile +993 -85
- data/guides/source/activerecord_validations_callbacks.textile +3 -3
- data/guides/source/caching_with_rails.textile +1 -1
- data/guides/source/command_line.textile +90 -88
- data/guides/source/configuring.textile +10 -10
- data/guides/source/contribute.textile +2 -2
- data/guides/source/contributing_to_rails.textile +14 -7
- data/guides/source/credits.textile.erb +8 -0
- data/guides/source/debugging_rails_applications.textile +6 -6
- data/guides/source/form_helpers.textile +1 -1
- data/guides/source/generators.textile +14 -14
- data/guides/source/getting_started.textile +634 -500
- data/guides/source/index.textile.erb +16 -1
- data/guides/source/layout.html.erb +7 -1
- data/guides/source/layouts_and_rendering.textile +299 -71
- data/guides/source/migrations.textile +5 -5
- data/guides/source/performance_testing.textile +8 -8
- data/guides/source/plugins.textile +26 -24
- data/guides/source/rails_on_rack.textile +5 -5
- data/guides/source/routing.textile +119 -117
- data/guides/source/security.textile +1 -1
- data/guides/source/testing.textile +4 -4
- data/lib/rails.rb +4 -1
- data/lib/rails/application.rb +44 -7
- data/lib/rails/application/bootstrap.rb +2 -14
- data/lib/rails/application/configuration.rb +69 -5
- data/lib/rails/application/finisher.rb +2 -3
- data/lib/rails/application/metal_loader.rb +1 -1
- data/lib/rails/application/routes_reloader.rb +1 -1
- data/lib/rails/backtrace_cleaner.rb +0 -11
- data/lib/rails/commands.rb +7 -6
- data/lib/rails/commands/application.rb +1 -1
- data/lib/rails/commands/console.rb +1 -1
- data/lib/rails/commands/dbconsole.rb +12 -0
- data/lib/rails/commands/destroy.rb +2 -2
- data/lib/rails/commands/generate.rb +2 -2
- data/lib/rails/commands/performance/benchmarker.rb +2 -2
- data/lib/rails/commands/performance/profiler.rb +2 -2
- data/lib/rails/commands/plugin.rb +6 -6
- data/lib/rails/commands/runner.rb +2 -0
- data/lib/rails/commands/server.rb +23 -8
- data/lib/rails/configuration.rb +2 -84
- data/lib/rails/console/app.rb +4 -3
- data/lib/rails/console/helpers.rb +3 -1
- data/lib/rails/engine.rb +107 -12
- data/lib/rails/engine/configuration.rb +8 -2
- data/lib/rails/generators.rb +22 -7
- data/lib/rails/generators/actions.rb +16 -6
- data/lib/rails/generators/base.rb +15 -8
- data/lib/rails/generators/erb.rb +21 -0
- data/lib/{generators → rails/generators}/erb/controller/controller_generator.rb +4 -5
- data/lib/{generators → rails/generators}/erb/controller/templates/view.html.erb +0 -0
- data/lib/rails/generators/erb/mailer/mailer_generator.rb +13 -0
- data/lib/{generators → rails/generators}/erb/mailer/templates/view.text.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/scaffold_generator.rb +14 -26
- data/lib/{generators → rails/generators}/erb/scaffold/templates/_form.html.erb +1 -1
- data/lib/{generators → rails/generators}/erb/scaffold/templates/edit.html.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/index.html.erb +1 -1
- data/lib/{generators → rails/generators}/erb/scaffold/templates/layout.html.erb +1 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/new.html.erb +0 -0
- data/lib/{generators → rails/generators}/erb/scaffold/templates/show.html.erb +0 -0
- data/lib/rails/generators/named_base.rb +4 -0
- data/lib/{generators → rails/generators}/rails/app/USAGE +0 -0
- data/lib/{generators → rails/generators}/rails/app/app_generator.rb +21 -7
- data/lib/rails/generators/rails/app/templates/Gemfile +34 -0
- data/lib/{generators → rails/generators}/rails/app/templates/README +9 -8
- data/lib/{generators → rails/generators}/rails/app/templates/Rakefile +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/controllers/application_controller.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/helpers/application_helper.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/models/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/app/views/layouts/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config.ru +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/application.rb +4 -3
- data/lib/rails/generators/rails/app/templates/config/boot.rb +14 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/frontbase.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/ibm_db.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/mysql.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/oracle.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/postgresql.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/databases/sqlite3.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environment.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/development.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/production.rb.tt +9 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/environments/test.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/backtrace_silencers.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/cookie_verification_secret.rb.tt +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/inflections.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/initializers/mime_types.rb +0 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +10 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/locales/en.yml +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/config/routes.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/db/seeds.rb +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/doc/README_FOR_APP +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/gitignore +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/404.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/422.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/500.html +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/favicon.ico +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/images/rails.png +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/index.html +17 -17
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/application.js +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/controls.js +5 -3
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/dragdrop.js +7 -6
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/effects.js +8 -13
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/prototype.js +1573 -1019
- data/lib/{generators → rails/generators}/rails/app/templates/public/javascripts/rails.js +1 -2
- data/lib/{generators → rails/generators}/rails/app/templates/public/robots.txt +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/public/stylesheets/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/script/rails +0 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/fixtures/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/functional/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/integration/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/app/templates/test/performance/browsing_test.rb +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/test_helper.rb +1 -1
- data/lib/{generators → rails/generators}/rails/app/templates/test/unit/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/controller/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/controller/controller_generator.rb +6 -0
- data/lib/{generators → rails/generators}/rails/controller/templates/controller.rb +0 -0
- data/lib/{generators → rails/generators}/rails/generator/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/generator/generator_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/generator/templates/%file_name%_generator.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/generator/templates/USAGE.tt +1 -1
- data/lib/{generators → rails/generators}/rails/generator/templates/templates/.empty_directory +0 -0
- data/lib/{generators → rails/generators}/rails/helper/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/helper/helper_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/helper/templates/helper.rb +0 -0
- data/lib/{generators → rails/generators}/rails/integration_test/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/integration_test/integration_test_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/mailer/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/mailer/mailer_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/mailer/templates/mailer.rb +0 -0
- data/lib/{generators → rails/generators}/rails/metal/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/metal/metal_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/metal/templates/metal.rb +0 -0
- data/lib/{generators → rails/generators}/rails/migration/USAGE +2 -2
- data/lib/{generators → rails/generators}/rails/migration/migration_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/model/USAGE +2 -2
- data/lib/{generators → rails/generators}/rails/model/model_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/observer/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/observer/observer_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/performance_test/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/performance_test/performance_test_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/plugin/plugin_generator.rb +1 -1
- data/lib/{generators → rails/generators}/rails/plugin/templates/MIT-LICENSE.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/README.tt +0 -0
- data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +23 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/init.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/install.rb +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/lib/%file_name%.rb.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/lib/tasks/%file_name%_tasks.rake.tt +0 -0
- data/lib/{generators → rails/generators}/rails/plugin/templates/uninstall.rb +0 -0
- data/lib/{generators → rails/generators}/rails/resource/USAGE +3 -3
- data/lib/{generators → rails/generators}/rails/resource/resource_generator.rb +3 -1
- data/lib/{generators → rails/generators}/rails/scaffold/USAGE +4 -4
- data/lib/{generators → rails/generators}/rails/scaffold/scaffold_generator.rb +1 -1
- data/lib/{generators → rails/generators}/rails/scaffold_controller/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/scaffold_controller/scaffold_controller_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/scaffold_controller/templates/controller.rb +2 -2
- data/lib/{generators → rails/generators}/rails/session_migration/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/session_migration/session_migration_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/stylesheets/USAGE +1 -1
- data/lib/{generators → rails/generators}/rails/stylesheets/stylesheets_generator.rb +0 -0
- data/lib/{generators → rails/generators}/rails/stylesheets/templates/scaffold.css +4 -0
- data/lib/{generators → rails/generators}/test_unit.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/controller/controller_generator.rb +2 -1
- data/lib/rails/generators/test_unit/controller/templates/functional_test.rb +18 -0
- data/lib/{generators → rails/generators}/test_unit/helper/helper_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/helper/templates/helper_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/integration/integration_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/integration/templates/integration_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/mailer/mailer_generator.rb +1 -8
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +20 -0
- data/lib/{generators → rails/generators}/test_unit/model/model_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/model/templates/fixtures.yml +0 -0
- data/lib/{generators → rails/generators}/test_unit/model/templates/unit_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/observer/observer_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/observer/templates/unit_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/performance/performance_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/performance/templates/performance_test.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/plugin/plugin_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/plugin/templates/%file_name%_test.rb.tt +0 -0
- data/lib/{generators → rails/generators}/test_unit/plugin/templates/test_helper.rb +0 -0
- data/lib/{generators → rails/generators}/test_unit/scaffold/scaffold_generator.rb +1 -1
- data/lib/{generators → rails/generators}/test_unit/scaffold/templates/functional_test.rb +9 -5
- data/{builtin/rails_info → lib}/rails/info.rb +0 -0
- data/{builtin/rails_info → lib}/rails/info_controller.rb +0 -0
- data/{builtin/routes.rb → lib/rails/info_routes.rb} +2 -2
- data/lib/rails/{subscriber.rb → log_subscriber.rb} +27 -27
- data/lib/rails/{subscriber → log_subscriber}/test_helper.rb +15 -16
- data/lib/rails/plugin.rb +31 -8
- data/lib/rails/rack/debugger.rb +3 -1
- data/lib/rails/rack/logger.rb +4 -4
- data/lib/rails/railtie.rb +179 -16
- data/lib/rails/railtie/configuration.rb +56 -1
- data/lib/rails/tasks/documentation.rake +38 -20
- data/lib/rails/tasks/framework.rake +16 -9
- data/lib/rails/tasks/misc.rake +3 -5
- data/lib/rails/tasks/routes.rake +2 -2
- data/lib/rails/test_help.rb +21 -1
- data/lib/rails/test_unit/railtie.rb +1 -3
- data/lib/rails/version.rb +3 -2
- metadata +199 -171
- data/builtin/rails_info/rails/info_helper.rb +0 -2
- data/lib/generators/erb.rb +0 -8
- data/lib/generators/erb/mailer/mailer_generator.rb +0 -20
- data/lib/generators/rails/app/templates/Gemfile +0 -34
- data/lib/generators/rails/app/templates/config/boot.rb +0 -17
- data/lib/generators/rails/app/templates/config/initializers/session_store.rb.tt +0 -15
- data/lib/generators/rails/model_subclass/model_subclass_generator.rb +0 -12
- data/lib/generators/rails/plugin/templates/Rakefile.tt +0 -10
- data/lib/generators/test_unit/controller/templates/functional_test.rb +0 -8
- data/lib/generators/test_unit/mailer/templates/fixture +0 -3
- data/lib/generators/test_unit/mailer/templates/functional_test.rb +0 -22
- data/lib/rails/railties_path.rb +0 -1
@@ -625,9 +625,9 @@ class ClientsController < ApplicationController
|
|
625
625
|
# returns it. The user will get the PDF as a file download.
|
626
626
|
def download_pdf
|
627
627
|
client = Client.find(params[:id])
|
628
|
-
send_data(
|
628
|
+
send_data generate_pdf(client),
|
629
629
|
:filename => "#{client.name}.pdf",
|
630
|
-
:type => "application/pdf"
|
630
|
+
:type => "application/pdf"
|
631
631
|
end
|
632
632
|
|
633
633
|
private
|
@@ -4,7 +4,7 @@ This guide should provide you with all you need to get started in sending and re
|
|
4
4
|
|
5
5
|
endprologue.
|
6
6
|
|
7
|
-
WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in
|
7
|
+
WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in earlier versions of Rails.
|
8
8
|
|
9
9
|
h3. Introduction
|
10
10
|
|
@@ -19,7 +19,7 @@ h4. Walkthrough to Generating a Mailer
|
|
19
19
|
h5. Create the Mailer
|
20
20
|
|
21
21
|
<shell>
|
22
|
-
|
22
|
+
rails generate mailer UserMailer
|
23
23
|
create app/mailers/user_mailer.rb
|
24
24
|
invoke erb
|
25
25
|
create app/views/user_mailer
|
@@ -111,7 +111,7 @@ Let's see how we would go about wiring it up using an observer.
|
|
111
111
|
First off, we need to create a simple +User+ scaffold:
|
112
112
|
|
113
113
|
<shell>
|
114
|
-
$
|
114
|
+
$ rails generate scaffold user name:string email:string login:string
|
115
115
|
$ rake db:migrate
|
116
116
|
</shell>
|
117
117
|
|
@@ -333,7 +333,7 @@ Receiving and parsing emails with Action Mailer can be a rather complex endeavou
|
|
333
333
|
|
334
334
|
* Implement a +receive+ method in your mailer.
|
335
335
|
|
336
|
-
* Configure your email server to forward emails from the address(es) you would like your app to receive to +/path/to/app/script/runner 'UserMailer.receive(STDIN.read)'+.
|
336
|
+
* Configure your email server to forward emails from the address(es) you would like your app to receive to +/path/to/app/script/rails runner 'UserMailer.receive(STDIN.read)'+.
|
337
337
|
|
338
338
|
Once a method called +receive+ is defined in any mailer, Action Mailer will parse the raw incoming email into an email object, decode it, instantiate a new mailer, and pass the email object to the mailer +receive+ instance method. Here's an example:
|
339
339
|
|
@@ -33,13 +33,13 @@ gem install actionpack
|
|
33
33
|
gem install rack
|
34
34
|
</shell>
|
35
35
|
|
36
|
-
Now we'll create a simple "Hello World" application that uses the +titleize+ method provided by
|
36
|
+
Now we'll create a simple "Hello World" application that uses the +titleize+ method provided by Active Support.
|
37
37
|
|
38
38
|
*hello_world.rb:*
|
39
39
|
|
40
40
|
<ruby>
|
41
41
|
require 'rubygems'
|
42
|
-
require '
|
42
|
+
require 'active_support/core_ext/string/inflections'
|
43
43
|
require 'rack'
|
44
44
|
|
45
45
|
def hello_world(env)
|
@@ -11,6 +11,8 @@ This guide covers different ways to retrieve data from the database using Active
|
|
11
11
|
|
12
12
|
endprologue.
|
13
13
|
|
14
|
+
WARNING. This Guide is based on Rails 3.0. Some of the code shown here will not work in other versions of Rails.
|
15
|
+
|
14
16
|
If you're used to using raw SQL to find database records then, generally, you will find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
|
15
17
|
|
16
18
|
Code examples throughout this guide will refer to one or more of the following models:
|
@@ -49,7 +51,22 @@ Active Record will perform queries on the database for you and is compatible wit
|
|
49
51
|
|
50
52
|
h3. Retrieving Objects from the Database
|
51
53
|
|
52
|
-
To retrieve objects from the database, Active Record provides
|
54
|
+
To retrieve objects from the database, Active Record provides several finder methods. These methods allows you to pass arguments into it to perform certain queries on your database without the need of writing raw SQL.
|
55
|
+
|
56
|
+
The methods are:
|
57
|
+
* +where+
|
58
|
+
* +select+
|
59
|
+
* +group+
|
60
|
+
* +order+
|
61
|
+
* +limit+
|
62
|
+
* +offset+
|
63
|
+
* +joins+
|
64
|
+
* +includes+
|
65
|
+
* +lock+
|
66
|
+
* +readonly+
|
67
|
+
* +from+
|
68
|
+
|
69
|
+
All of these methods return a Relation
|
53
70
|
|
54
71
|
Primary operation of <tt>Model.find(options)</tt> can be summarized as:
|
55
72
|
|
@@ -64,7 +81,7 @@ Active Record lets you retrieve a single object using three different ways.
|
|
64
81
|
|
65
82
|
h5. Using a Primary Key
|
66
83
|
|
67
|
-
Using <tt>Model.find(primary_key
|
84
|
+
Using <tt>Model.find(primary_key)</tt>, you can retrieve the object corresponding to the supplied _primary key_ and matching the supplied options (if any). For example:
|
68
85
|
|
69
86
|
<ruby>
|
70
87
|
# Find the client with primary key (id) 10.
|
@@ -82,7 +99,7 @@ SELECT * FROM clients WHERE (clients.id = 10)
|
|
82
99
|
|
83
100
|
h5. +first+
|
84
101
|
|
85
|
-
<tt>Model.first
|
102
|
+
<tt>Model.first</tt> finds the first record matched by the supplied options. For example:
|
86
103
|
|
87
104
|
<ruby>
|
88
105
|
client = Client.first
|
@@ -97,11 +114,9 @@ SELECT * FROM clients LIMIT 1
|
|
97
114
|
|
98
115
|
<tt>Model.first</tt> returns +nil+ if no matching record is found. No exception will be raised.
|
99
116
|
|
100
|
-
NOTE: +Model.find(:first, options)+ is equivalent to +Model.first(options)+
|
101
|
-
|
102
117
|
h5. +last+
|
103
118
|
|
104
|
-
<tt>Model.last
|
119
|
+
<tt>Model.last</tt> finds the last record matched by the supplied options. For example:
|
105
120
|
|
106
121
|
<ruby>
|
107
122
|
client = Client.last
|
@@ -116,13 +131,11 @@ SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1
|
|
116
131
|
|
117
132
|
<tt>Model.last</tt> returns +nil+ if no matching record is found. No exception will be raised.
|
118
133
|
|
119
|
-
NOTE: +Model.find(:last, options)+ is equivalent to +Model.last(options)+
|
120
|
-
|
121
134
|
h4. Retrieving Multiple Objects
|
122
135
|
|
123
136
|
h5. Using Multiple Primary Keys
|
124
137
|
|
125
|
-
<tt>Model.find(array_of_primary_key
|
138
|
+
<tt>Model.find(array_of_primary_key)</tt> also accepts an array of _primary keys_. An array of all the matching records for the supplied _primary keys_ is returned. For example:
|
126
139
|
|
127
140
|
<ruby>
|
128
141
|
# Find the clients with primary keys 1 and 10.
|
@@ -138,26 +151,6 @@ SELECT * FROM clients WHERE (clients.id IN (1,10))
|
|
138
151
|
|
139
152
|
<tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for <strong>all</strong> of the supplied primary keys.
|
140
153
|
|
141
|
-
h5. Find all
|
142
|
-
|
143
|
-
<tt>Model.all(options = nil)</tt> finds all the records matching the supplied +options+. If no +options+ are supplied, all rows from the database are returned.
|
144
|
-
|
145
|
-
<ruby>
|
146
|
-
# Find all the clients.
|
147
|
-
clients = Client.all
|
148
|
-
=> [#<Client id: 1, name: => "Lifo">, #<Client id: 10, name: => "Ryan">, #<Client id: 221, name: => "Russel">]
|
149
|
-
</ruby>
|
150
|
-
|
151
|
-
And the equivalent SQL is:
|
152
|
-
|
153
|
-
<sql>
|
154
|
-
SELECT * FROM clients
|
155
|
-
</sql>
|
156
|
-
|
157
|
-
<tt>Model.all</tt> returns an empty array +[]+ if no matching record is found. No exception will be raised.
|
158
|
-
|
159
|
-
NOTE: +Model.find(:all, options)+ is equivalent to +Model.all(options)+
|
160
|
-
|
161
154
|
h4. Retrieving Multiple Objects in Batches
|
162
155
|
|
163
156
|
Sometimes you need to iterate over a large set of records. For example to send a newsletter to all users, to export some data, etc.
|
@@ -166,14 +159,14 @@ The following may seem very straight forward at first:
|
|
166
159
|
|
167
160
|
<ruby>
|
168
161
|
# Very inefficient when users table has thousands of rows.
|
169
|
-
User.
|
162
|
+
User.each do |user|
|
170
163
|
NewsLetter.weekly_deliver(user)
|
171
164
|
end
|
172
165
|
</ruby>
|
173
166
|
|
174
167
|
But if the total number of rows in the table is very large, the above approach may vary from being under performant to just plain impossible.
|
175
168
|
|
176
|
-
This is because +User.
|
169
|
+
This is because +User.each+ makes Active Record fetch _the entire table_, build a model object per row, and keep the entire array in the memory. Sometimes that is just too many objects and demands too much memory.
|
177
170
|
|
178
171
|
h5. +find_each+
|
179
172
|
|
@@ -232,16 +225,16 @@ The +find+ method allows you to specify conditions to limit the records returned
|
|
232
225
|
|
233
226
|
h4. Pure String Conditions
|
234
227
|
|
235
|
-
If you'd like to add conditions to your find, you could just specify them in there, just like +Client.
|
228
|
+
If you'd like to add conditions to your find, you could just specify them in there, just like +Client.where("orders_count = '2'")+. This will find all clients where the +orders_count+ field's value is 2.
|
236
229
|
|
237
|
-
WARNING: Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. For example, +Client.
|
230
|
+
WARNING: Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. For example, +Client.where("name LIKE '%#{params[:name]}%'")+ is not safe. See the next section for the preferred way to handle conditions using an array.
|
238
231
|
|
239
232
|
h4. Array Conditions
|
240
233
|
|
241
234
|
Now what if that number could vary, say as an argument from somewhere, or perhaps from the user's level status somewhere? The find then becomes something like:
|
242
235
|
|
243
236
|
<ruby>
|
244
|
-
Client.
|
237
|
+
Client.where(["orders_count = ?", params[:orders]])
|
245
238
|
</ruby>
|
246
239
|
|
247
240
|
Active Record will go through the first element in the conditions value and any additional elements will replace the question marks +(?)+ in the first element.
|
@@ -249,7 +242,7 @@ Active Record will go through the first element in the conditions value and any
|
|
249
242
|
Or if you want to specify two conditions, you can do it like:
|
250
243
|
|
251
244
|
<ruby>
|
252
|
-
Client.
|
245
|
+
Client.where(["orders_count = ? AND locked = ?", params[:orders], false])
|
253
246
|
</ruby>
|
254
247
|
|
255
248
|
In this example, the first question mark will be replaced with the value in +params[:orders]+ and the second will be replaced with the SQL representation of +false+, which depends on the adapter.
|
@@ -257,13 +250,13 @@ In this example, the first question mark will be replaced with the value in +par
|
|
257
250
|
The reason for doing code like:
|
258
251
|
|
259
252
|
<ruby>
|
260
|
-
Client.
|
253
|
+
Client.where(["orders_count = ?", params[:orders]])
|
261
254
|
</ruby>
|
262
255
|
|
263
256
|
instead of:
|
264
257
|
|
265
258
|
<ruby>
|
266
|
-
Client.
|
259
|
+
Client.where("orders_count = #{params[:orders]}")
|
267
260
|
</ruby>
|
268
261
|
|
269
262
|
is because of argument safety. Putting the variable directly into the conditions string will pass the variable to the database *as-is*. This means that it will be an unescaped variable directly from a user who may have malicious intent. If you do this, you put your entire database at risk because once a user finds out he or she can exploit your database they can do just about anything to it. Never ever put your arguments directly inside the conditions string.
|
@@ -275,7 +268,7 @@ h5. Placeholder Conditions
|
|
275
268
|
Similar to the +(?)+ replacement style of params, you can also specify keys/values hash in your array conditions:
|
276
269
|
|
277
270
|
<ruby>
|
278
|
-
Client.
|
271
|
+
Client.where(
|
279
272
|
["created_at >= :start_date AND created_at <= :end_date", { :start_date => params[:start_date], :end_date => params[:end_date] }])
|
280
273
|
</ruby>
|
281
274
|
|
@@ -286,7 +279,7 @@ h5. Range Conditions
|
|
286
279
|
If you're looking for a range inside of a table (for example, users created in a certain timeframe) you can use the conditions option coupled with the +IN+ SQL statement for this. If you had two dates coming in from a controller you could do something like this to look for a range:
|
287
280
|
|
288
281
|
<ruby>
|
289
|
-
Client.
|
282
|
+
Client.where(["created_at IN (?)",
|
290
283
|
(params[:start_date].to_date)..(params[:end_date].to_date)])
|
291
284
|
</ruby>
|
292
285
|
|
@@ -308,7 +301,7 @@ h5. Time and Date Conditions
|
|
308
301
|
Things can get *really* messy if you pass in Time objects as it will attempt to compare your field to *every second* in that range:
|
309
302
|
|
310
303
|
<ruby>
|
311
|
-
Client.
|
304
|
+
Client.where(["created_at IN (?)",
|
312
305
|
(params[:start_date].to_date.to_time)..(params[:end_date].to_date.to_time)])
|
313
306
|
</ruby>
|
314
307
|
|
@@ -329,14 +322,14 @@ Where _query_ is the actual query used to get that error.
|
|
329
322
|
In this example it would be better to use greater-than and less-than operators in SQL, like so:
|
330
323
|
|
331
324
|
<ruby>
|
332
|
-
Client.
|
325
|
+
Client.where(
|
333
326
|
["created_at > ? AND created_at < ?", params[:start_date], params[:end_date]])
|
334
327
|
</ruby>
|
335
328
|
|
336
329
|
You can also use the greater-than-or-equal-to and less-than-or-equal-to like this:
|
337
330
|
|
338
331
|
<ruby>
|
339
|
-
Client.
|
332
|
+
Client.where(
|
340
333
|
["created_at >= ? AND created_at <= ?", params[:start_date], params[:end_date]])
|
341
334
|
</ruby>
|
342
335
|
|
@@ -351,13 +344,13 @@ NOTE: Only equality, range and subset checking are possible with Hash conditions
|
|
351
344
|
h5. Equality Conditions
|
352
345
|
|
353
346
|
<ruby>
|
354
|
-
Client.
|
347
|
+
Client.where({ :locked => true })
|
355
348
|
</ruby>
|
356
349
|
|
357
350
|
The field name does not have to be a symbol it can also be a string:
|
358
351
|
|
359
352
|
<ruby>
|
360
|
-
Client.
|
353
|
+
Client.where({ 'locked' => true })
|
361
354
|
</ruby>
|
362
355
|
|
363
356
|
h5. Range Conditions
|
@@ -365,7 +358,7 @@ h5. Range Conditions
|
|
365
358
|
The good thing about this is that we can pass in a range for our fields without it generating a large query as shown in the preamble of this section.
|
366
359
|
|
367
360
|
<ruby>
|
368
|
-
Client.
|
361
|
+
Client.where({ :created_at => (Time.now.midnight - 1.day)..Time.now.midnight})
|
369
362
|
</ruby>
|
370
363
|
|
371
364
|
This will find all clients created yesterday by using a +BETWEEN+ SQL statement:
|
@@ -381,7 +374,7 @@ h5. Subset Conditions
|
|
381
374
|
If you want to find records using the +IN+ expression you can pass an array to the conditions hash:
|
382
375
|
|
383
376
|
<ruby>
|
384
|
-
Client.
|
377
|
+
Client.where({ :orders_count => [1,3,5] })
|
385
378
|
</ruby>
|
386
379
|
|
387
380
|
This code will generate SQL like this:
|
@@ -390,22 +383,6 @@ This code will generate SQL like this:
|
|
390
383
|
SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
|
391
384
|
</sql>
|
392
385
|
|
393
|
-
h3. Find Options
|
394
|
-
|
395
|
-
Apart from +:conditions+, +Model.find+ takes a variety of other options via the options hash for customizing the resulting record set.
|
396
|
-
|
397
|
-
<ruby>
|
398
|
-
Model.find(id_or_array_of_ids, options_hash)
|
399
|
-
Model.find(:last, options_hash)
|
400
|
-
Model.find(:first, options_hash)
|
401
|
-
|
402
|
-
Model.first(options_hash)
|
403
|
-
Model.last(options_hash)
|
404
|
-
Model.all(options_hash)
|
405
|
-
</ruby>
|
406
|
-
|
407
|
-
The following sections give a top level overview of all the possible keys for the +options_hash+.
|
408
|
-
|
409
386
|
h4. Ordering
|
410
387
|
|
411
388
|
To retrieve records from the database in a specific order, you can specify the +:order+ option to the +find+ call.
|
@@ -413,37 +390,37 @@ To retrieve records from the database in a specific order, you can specify the +
|
|
413
390
|
For example, if you're getting a set of records and want to order them in ascending order by the +created_at+ field in your table:
|
414
391
|
|
415
392
|
<ruby>
|
416
|
-
Client.
|
393
|
+
Client.order("created_at")
|
417
394
|
</ruby>
|
418
395
|
|
419
396
|
You could specify +ASC+ or +DESC+ as well:
|
420
397
|
|
421
398
|
<ruby>
|
422
|
-
Client.
|
399
|
+
Client.order("created_at DESC")
|
423
400
|
# OR
|
424
|
-
Client.
|
401
|
+
Client.order("created_at ASC")
|
425
402
|
</ruby>
|
426
403
|
|
427
404
|
Or ordering by multiple fields:
|
428
405
|
|
429
406
|
<ruby>
|
430
|
-
Client.
|
407
|
+
Client.order("orders_count ASC, created_at DESC")
|
431
408
|
</ruby>
|
432
409
|
|
433
410
|
h4. Selecting Specific Fields
|
434
411
|
|
435
412
|
By default, <tt>Model.find</tt> selects all the fields from the result set using +select *+.
|
436
413
|
|
437
|
-
To select only a subset of fields from the result set, you can specify the subset via
|
414
|
+
To select only a subset of fields from the result set, you can specify the subset via the +select+ method.
|
438
415
|
|
439
|
-
NOTE: If the
|
416
|
+
NOTE: If the +select+ method is used, all the returning objects will be "read only":#readonly-objects.
|
440
417
|
|
441
418
|
<br />
|
442
419
|
|
443
420
|
For example, to select only +viewable_by+ and +locked+ columns:
|
444
421
|
|
445
422
|
<ruby>
|
446
|
-
Client.
|
423
|
+
Client.select("viewable_by, locked")
|
447
424
|
</ruby>
|
448
425
|
|
449
426
|
The SQL query used by this find call will be somewhat like:
|
@@ -463,17 +440,17 @@ Where +<attribute>+ is the attribute you asked for. The +id+ method will n
|
|
463
440
|
You can also call SQL functions within the select option. For example, if you would like to only grab a single record per unique value in a certain field by using the +DISTINCT+ function you can do it like this:
|
464
441
|
|
465
442
|
<ruby>
|
466
|
-
Client.
|
443
|
+
Client.select("DISTINCT(name)")
|
467
444
|
</ruby>
|
468
445
|
|
469
446
|
h4. Limit and Offset
|
470
447
|
|
471
|
-
To apply +LIMIT+ to the SQL fired by the +Model.find+, you can specify the +LIMIT+ using
|
448
|
+
To apply +LIMIT+ to the SQL fired by the +Model.find+, you can specify the +LIMIT+ using +limit+ and +offset+ methods on the relation.
|
472
449
|
|
473
|
-
If you want to limit the amount of records to a certain subset of all the records retrieved you usually use
|
450
|
+
If you want to limit the amount of records to a certain subset of all the records retrieved you usually use +limit+ for this, sometimes coupled with +offset+. Limit is the maximum number of records that will be retrieved from a query, and offset is the number of records it will start reading from from the first record of the set. For example:
|
474
451
|
|
475
452
|
<ruby>
|
476
|
-
Client.
|
453
|
+
Client.limit(5)
|
477
454
|
</ruby>
|
478
455
|
|
479
456
|
This code will return a maximum of 5 clients and because it specifies no offset it will return the first 5 clients in the table. The SQL it executes will look like this:
|
@@ -482,10 +459,10 @@ This code will return a maximum of 5 clients and because it specifies no offset
|
|
482
459
|
SELECT * FROM clients LIMIT 5
|
483
460
|
</sql>
|
484
461
|
|
485
|
-
Or
|
462
|
+
Or chaining both +limit+ and +offset+:
|
486
463
|
|
487
464
|
<ruby>
|
488
|
-
Client.
|
465
|
+
Client.limit(5).offset(5)
|
489
466
|
</ruby>
|
490
467
|
|
491
468
|
This code will return a maximum of 5 clients and because it specifies an offset this time, it will return these records starting from the 5th client in the clients table. The SQL looks like:
|
@@ -496,12 +473,12 @@ SELECT * FROM clients LIMIT 5, 5
|
|
496
473
|
|
497
474
|
h4. Group
|
498
475
|
|
499
|
-
To apply +GROUP BY+ clause to the SQL fired by the
|
476
|
+
To apply +GROUP BY+ clause to the SQL fired by the finder, you can specify the +group+ method on the find.
|
500
477
|
|
501
478
|
For example, if you want to find a collection of the dates orders were created on:
|
502
479
|
|
503
480
|
<ruby>
|
504
|
-
Order.
|
481
|
+
Order.group("date(created_at)").order("created_at")
|
505
482
|
</ruby>
|
506
483
|
|
507
484
|
And this will give you a single +Order+ object for each date where there are orders in the database.
|
@@ -519,7 +496,7 @@ SQL uses +HAVING+ clause to specify conditions on the +GROUP BY+ fields. You can
|
|
519
496
|
For example:
|
520
497
|
|
521
498
|
<ruby>
|
522
|
-
Order.
|
499
|
+
Order.group("date(created_at)".having(["created_at > ?", 1.month.ago])
|
523
500
|
</ruby>
|
524
501
|
|
525
502
|
The SQL that would be executed would be something like this:
|
@@ -532,18 +509,18 @@ This will return single order objects for each day, but only for the last month.
|
|
532
509
|
|
533
510
|
h4. Readonly Objects
|
534
511
|
|
535
|
-
To explicitly disallow modification/destruction of the matching records returned
|
512
|
+
To explicitly disallow modification/destruction of the matching records returned in a Relation object, you could chain the +readonly+ method as +true+ to the find call.
|
536
513
|
|
537
514
|
Any attempt to alter or destroy the readonly records will not succeed, raising an +ActiveRecord::ReadOnlyRecord+ exception. To set this option, specify it like this:
|
538
515
|
|
539
516
|
<ruby>
|
540
|
-
Client.first(
|
517
|
+
Client.first.readonly(true)
|
541
518
|
</ruby>
|
542
519
|
|
543
520
|
If you assign this record to a variable client, calling the following code will raise an +ActiveRecord::ReadOnlyRecord+ exception:
|
544
521
|
|
545
522
|
<ruby>
|
546
|
-
client = Client.first(
|
523
|
+
client = Client.first.readonly(true)
|
547
524
|
client.locked = false
|
548
525
|
client.save
|
549
526
|
</ruby>
|
@@ -676,7 +653,7 @@ Now all of the following will produce the expected join queries using +INNER JOI
|
|
676
653
|
h5. Joining a Single Association
|
677
654
|
|
678
655
|
<ruby>
|
679
|
-
Category.
|
656
|
+
Category.joins(:posts)
|
680
657
|
</ruby>
|
681
658
|
|
682
659
|
This produces:
|
@@ -689,7 +666,7 @@ SELECT categories.* FROM categories
|
|
689
666
|
h5. Joining Multiple Associations
|
690
667
|
|
691
668
|
<ruby>
|
692
|
-
Post.
|
669
|
+
Post.joins(:category, :comments)
|
693
670
|
</ruby>
|
694
671
|
|
695
672
|
This produces:
|
@@ -703,13 +680,13 @@ SELECT posts.* FROM posts
|
|
703
680
|
h5. Joining Nested Associations (Single Level)
|
704
681
|
|
705
682
|
<ruby>
|
706
|
-
Post.
|
683
|
+
Post.joins(:comments => :guest)
|
707
684
|
</ruby>
|
708
685
|
|
709
686
|
h5. Joining Nested Associations (Multiple Level)
|
710
687
|
|
711
688
|
<ruby>
|
712
|
-
Category.
|
689
|
+
Category.joins(:posts => [{:comments => :guest}, :tags])
|
713
690
|
</ruby>
|
714
691
|
|
715
692
|
h4. Specifying Conditions on the Joined Tables
|
@@ -718,14 +695,14 @@ You can specify conditions on the joined tables using the regular "Array":#array
|
|
718
695
|
|
719
696
|
<ruby>
|
720
697
|
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
|
721
|
-
Client.
|
698
|
+
Client.joins(:orders).where('orders.created_at' => time_range)
|
722
699
|
</ruby>
|
723
700
|
|
724
701
|
An alternative and cleaner syntax to this is to nest the hash conditions:
|
725
702
|
|
726
703
|
<ruby>
|
727
704
|
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
|
728
|
-
Client.
|
705
|
+
Client.joins(:orders).where(:orders => {:created_at => time_range})
|
729
706
|
</ruby>
|
730
707
|
|
731
708
|
This will find all clients who have orders that were created yesterday, again using a +BETWEEN+ SQL expression.
|
@@ -750,12 +727,12 @@ This code looks fine at the first sight. But the problem lies within the total n
|
|
750
727
|
|
751
728
|
<strong>Solution to N <plus> 1 queries problem</strong>
|
752
729
|
|
753
|
-
Active Record lets you specify all the associations in advanced that are going to be loaded. This is possible by specifying the
|
730
|
+
Active Record lets you specify all the associations in advanced that are going to be loaded. This is possible by specifying the +includes+ method of the +Model.find+ call. With +includes+, Active Record ensures that all the specified associations are loaded using minimum possible number of queries.
|
754
731
|
|
755
732
|
Revisiting the above case, we could rewrite +Client.all+ to use eager load addresses:
|
756
733
|
|
757
734
|
<ruby>
|
758
|
-
clients = Client.
|
735
|
+
clients = Client.includes(:address).limit(10)
|
759
736
|
|
760
737
|
clients.each do |client|
|
761
738
|
puts client.address.postcode
|
@@ -772,12 +749,12 @@ SELECT addresses.* FROM addresses
|
|
772
749
|
|
773
750
|
h4. Eager Loading Multiple Associations
|
774
751
|
|
775
|
-
Active Record lets you eager load any possible number of associations with a single +Model.find+ call by using an array, hash, or a nested hash of array/hash with the
|
752
|
+
Active Record lets you eager load any possible number of associations with a single +Model.find+ call by using an array, hash, or a nested hash of array/hash with the +includes+ method.
|
776
753
|
|
777
754
|
h5. Array of Multiple Associations
|
778
755
|
|
779
756
|
<ruby>
|
780
|
-
Post.
|
757
|
+
Post.includes(:category, :comments)
|
781
758
|
</ruby>
|
782
759
|
|
783
760
|
This loads all the posts and the associated category and comments for each post.
|
@@ -785,14 +762,14 @@ This loads all the posts and the associated category and comments for each post.
|
|
785
762
|
h5. Nested Associations Hash
|
786
763
|
|
787
764
|
<ruby>
|
788
|
-
Category.find
|
765
|
+
Category.find(1).includes(:posts => [{:comments => :guest}, :tags])
|
789
766
|
</ruby>
|
790
767
|
|
791
768
|
The above code finds the category with id 1 and eager loads all the posts associated with the found category. Additionally, it will also eager load every posts' tags and comments. Every comment's guest association will get eager loaded as well.
|
792
769
|
|
793
770
|
h4. Specifying Conditions on Eager Loaded Associations
|
794
771
|
|
795
|
-
Even though Active Record lets you specify conditions on the eager loaded associations just like
|
772
|
+
Even though Active Record lets you specify conditions on the eager loaded associations just like +joins+, the recommended way is to use "joins":#joining-tables instead.
|
796
773
|
|
797
774
|
h3. Dynamic Finders
|
798
775
|
|
@@ -889,10 +866,10 @@ Which will execute:
|
|
889
866
|
SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
|
890
867
|
</sql>
|
891
868
|
|
892
|
-
You can also use
|
869
|
+
You can also use the +includes+ or +joins+ methods for this to do something a little more complex:
|
893
870
|
|
894
871
|
<ruby>
|
895
|
-
Client.count(
|
872
|
+
Client.count.where("clients.first_name = 'Ryan' AND orders.status = 'received'").includes("orders")
|
896
873
|
</ruby>
|
897
874
|
|
898
875
|
Which will execute:
|
@@ -957,5 +934,6 @@ h3. Changelog
|
|
957
934
|
|
958
935
|
"Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/16
|
959
936
|
|
937
|
+
* February 3, 2010: Update to Rails 3 by "James Miller":credits.html#bensie
|
960
938
|
* February 7, 2009: Second version by "Pratik":credits.html#lifo
|
961
939
|
* December 29 2008: Initial version by "Ryan Bigg":credits.html#radar
|