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
data/CHANGELOG
CHANGED
@@ -1,25 +1,43 @@
|
|
1
|
+
*Rails 3.0.0 [release candidate] (July 26th, 2010)*
|
2
|
+
|
3
|
+
* Application generation: --skip-testunit and --skip-activerecord become --skip-test-unit
|
4
|
+
and --skip-active-record respectively. [fxn]
|
5
|
+
|
6
|
+
* Added console to Rails::Railtie as a hook called just after console starts. [José Valim]
|
7
|
+
|
8
|
+
* Rails no longer autoload code in lib for application. You need to explicitly require it. [José Valim]
|
9
|
+
|
10
|
+
* Rails::LogSubscriber was renamed to ActiveSupport::LogSubscriber [José Valim]
|
11
|
+
|
12
|
+
* config.load_(once_)paths in config/application.rb got renamed to config.autoload_(once_)paths. [fxn]
|
13
|
+
|
14
|
+
* Abort generation/booting on Ruby 1.9.1. [fxn]
|
15
|
+
|
16
|
+
* Made the rails command work even when you're in a subdirectory [Chad Fowler]
|
17
|
+
|
18
|
+
|
1
19
|
*Rails 3.0.0 [beta 4] (June 8th, 2010)*
|
2
20
|
|
3
|
-
*
|
4
|
-
|
21
|
+
* Removed Rails Metal [Yehuda Katz, José Valim].
|
22
|
+
|
5
23
|
|
6
24
|
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
7
25
|
|
8
|
-
* Renamed config.cookie_secret to config.secret_token and pass it as env key. [
|
26
|
+
* Renamed config.cookie_secret to config.secret_token and pass it as env key. [José Valim]
|
9
27
|
|
10
28
|
|
11
29
|
*Rails 3.0.0 [beta 2] (April 1st, 2010)*
|
12
30
|
|
13
|
-
* Session store configuration has changed [
|
31
|
+
* Session store configuration has changed [Yehuda Katz, Carl Lerche]
|
14
32
|
|
15
33
|
config.session_store :cookie_store, {:key => "..."}
|
16
34
|
config.cookie_secret = "fdsfhisdghfidugnfdlg"
|
17
35
|
|
18
36
|
* railtie_name and engine_name are deprecated. You can now add any object to
|
19
|
-
the configuration object: config.your_plugin = {} [
|
37
|
+
the configuration object: config.your_plugin = {} [José Valim]
|
20
38
|
|
21
39
|
* Added config.generators.templates to provide alternative paths for the generators
|
22
|
-
to look for templates [
|
40
|
+
to look for templates [José Valim]
|
23
41
|
|
24
42
|
*Rails 3.0.0 [beta 1] (February 4, 2010)*
|
25
43
|
|
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= Railties -- Gluing the Engine to the Rails
|
2
|
+
|
3
|
+
Railties is responsible to glue all frameworks together. Overall, it:
|
4
|
+
|
5
|
+
* handles all the bootstrapping process for a Rails application;
|
6
|
+
|
7
|
+
* manager rails command line interface;
|
8
|
+
|
9
|
+
* provides Rails generators core;
|
10
|
+
|
11
|
+
|
12
|
+
== Download
|
13
|
+
|
14
|
+
The latest version of Railties can be installed with Rubygems:
|
15
|
+
|
16
|
+
* gem install railties
|
17
|
+
|
18
|
+
Documentation can be found at
|
19
|
+
|
20
|
+
* http://api.rubyonrails.org
|
21
|
+
|
22
|
+
|
23
|
+
== License
|
24
|
+
|
25
|
+
Railties is released under the MIT license.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -32,11 +32,11 @@ h3. Upgrading to Rails 3
|
|
32
32
|
|
33
33
|
If you're upgrading an existing application, it's a great idea to have good test coverage before going in. You should also first upgrade to Rails 2.3.5 and make sure your application still runs as expected before attempting to update to Rails 3. Then take heed of the following changes:
|
34
34
|
|
35
|
-
h4. Rails 3 requires Ruby 1.8.7
|
35
|
+
h4. Rails 3 requires at least Ruby 1.8.7
|
36
36
|
|
37
37
|
Rails 3.0 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.0 is also compatible with Ruby 1.9.2.
|
38
38
|
|
39
|
-
TIP: Note that Ruby 1.8.7 p248 and p249
|
39
|
+
TIP: Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails 3.0. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults on Rails 3.0, so if you want to use Rails 3 with 1.9.x jump on 1.9.2 for smooth sailing.
|
40
40
|
|
41
41
|
h4. Rails Application object
|
42
42
|
|
@@ -339,7 +339,9 @@ h5. Other Changes
|
|
339
339
|
* You no longer need to place a minus sign at the end of a ruby interpolation inside an ERb template to remove the trailing carriage return in the HTML output.
|
340
340
|
* Added +grouped_collection_select+ helper to Action View.
|
341
341
|
* +content_for?+ has been added allowing you to check for the existence of content in a view before rendering.
|
342
|
-
|
342
|
+
* passing +:value => nil+ to form helpers will set the field's +value+ attribute to nil as opposed to using the default value
|
343
|
+
* passing +:id => nil+ to form helpers will cause those fields to be rendered with no +id+ attribute
|
344
|
+
* passing +:alt => nil+ to +image_tag+ will cause the +img+ tag to render with no +alt+ attribute
|
343
345
|
|
344
346
|
h3. Active Model
|
345
347
|
|
@@ -338,6 +338,25 @@ end
|
|
338
338
|
|
339
339
|
Note that while for session values you set the key to +nil+, to delete a cookie value you should use +cookies.delete(:key)+.
|
340
340
|
|
341
|
+
h3. Rendering xml and json data
|
342
|
+
|
343
|
+
ActionController makes it extremely easy to render +xml+ or +json+ data. If you generate a controller using scaffold then your controller would look something like this.
|
344
|
+
|
345
|
+
<ruby>
|
346
|
+
class UsersController < ApplicationController
|
347
|
+
def index
|
348
|
+
@users = User.all
|
349
|
+
respond_to do |format|
|
350
|
+
format.html # index.html.erb
|
351
|
+
format.xml { render :xml => @users}
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
</ruby>
|
356
|
+
|
357
|
+
Notice that in the above case code is <tt>render :xml => @users</tt> and not <tt>render :xml => @users.to_xml</tt>. That is because if the input is not string then rails automatically invokes +to_xml+ .
|
358
|
+
|
359
|
+
|
341
360
|
h3. Filters
|
342
361
|
|
343
362
|
Filters are methods that are run before, after or "around" a controller action.
|
@@ -32,16 +32,16 @@ Active Record gives us several mechanisms, the most important being the ability
|
|
32
32
|
* Validate models before they get persisted to the database
|
33
33
|
* Perform database operations in an object-oriented fashion.
|
34
34
|
|
35
|
-
h3. Convention over Configuration in
|
35
|
+
h3. Convention over Configuration in Active Record
|
36
36
|
|
37
|
-
When writing applications using other programming languages or frameworks, it may be necessary to write a lot of configuration code. This is particularly true for ORM frameworks in general. However, if you follow the conventions adopted by Rails, you'll need to write very little configuration (in some case no configuration at all) when creating
|
37
|
+
When writing applications using other programming languages or frameworks, it may be necessary to write a lot of configuration code. This is particularly true for ORM frameworks in general. However, if you follow the conventions adopted by Rails, you'll need to write very little configuration (in some case no configuration at all) when creating Active Record models. The idea is that if you configure your applications in the very same way most of the times then this should be the default way. In this cases, explicit configuration would be needed only in those cases where you can't follow the conventions for any reason.
|
38
38
|
|
39
39
|
h4. Naming Conventions
|
40
40
|
|
41
|
-
By default,
|
41
|
+
By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created. Rails will pluralize your class names to find the respective database table. So, for a class +Book+, you should have a database table called *books*. The Rails pluralization mechanisms are very powerful, being capable to pluralize (and singularize) both regular and irregular words. When using class names composed of two or more words, the model class name should follow the Ruby conventions, using the camelCase form, while the table name must contain the words separated by underscores. Examples:
|
42
42
|
|
43
|
-
* Database Table - Plural with underscores separating words
|
44
|
-
* Model Class - Singular with the first letter of each word capitalized
|
43
|
+
* Database Table - Plural with underscores separating words (e.g., book_clubs)
|
44
|
+
* Model Class - Singular with the first letter of each word capitalized (e.g., BookClub)
|
45
45
|
|
46
46
|
|_.Model / Class |_.Table / Schema |
|
47
47
|
|Post |posts|
|
@@ -53,30 +53,32 @@ By default, ActiveRecord uses some naming conventions to find out how the mappin
|
|
53
53
|
|
54
54
|
h4. Schema Conventions
|
55
55
|
|
56
|
-
|
56
|
+
Active Record uses naming conventions for the columns in database tables, depending on the purpose of these columns.
|
57
57
|
|
58
|
-
* *Foreign keys* - These fields should be named following the pattern table_id
|
59
|
-
* *Primary keys* - By default,
|
58
|
+
* *Foreign keys* - These fields should be named following the pattern table_id (e.g., item_id, order_id). These are the fields that Active Record will look for when you create associations between your models.
|
59
|
+
* *Primary keys* - By default, Active Record will use an integer column named "id" as the table's primary key. When using "Rails Migrations":migrations.html to create your tables, this column will be automatically created.
|
60
60
|
|
61
|
-
There are also some optional column names that will create additional features to
|
61
|
+
There are also some optional column names that will create additional features to Active Record instances:
|
62
62
|
|
63
|
-
* *created_at
|
64
|
-
* *
|
63
|
+
* *created_at* - Automatically gets set to the current date and time when the record is first created.
|
64
|
+
* *created_on* - Automatically gets set to the current date when the record is first created.
|
65
|
+
* *updated_at* - Automatically gets set to the current date and time whenever the record is updated.
|
66
|
+
* *updated_on* - Automatically gets set to the current date whenever the record is updated.
|
65
67
|
* *lock_version* - Adds "optimistic locking":http://api.rubyonrails.com/classes/ActiveRecord/Locking.html to a model.
|
66
68
|
* *type* - Specifies that the model uses "Single Table Inheritance":http://api.rubyonrails.com/classes/ActiveRecord/Base.html
|
67
69
|
* *(table_name)_count* - Used to cache the number of belonging objects on associations. For example, a +comments_count+ column in a +Post+ class that has many instances of +Comment+ will cache the number of existent comments for each post.
|
68
70
|
|
69
|
-
NOTE: While these column names are optional they are in fact reserved by
|
71
|
+
NOTE: While these column names are optional they are in fact reserved by Active Record. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
|
70
72
|
|
71
|
-
h3. Creating
|
73
|
+
h3. Creating Active Record Models
|
72
74
|
|
73
|
-
It's very easy to create
|
75
|
+
It's very easy to create Active Record models. All you have to do is to subclass the +ActiveRecord::Base+ class and you're good to go:
|
74
76
|
|
75
77
|
<ruby>
|
76
78
|
class Product < ActiveRecord::Base; end
|
77
79
|
</ruby>
|
78
80
|
|
79
|
-
This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using
|
81
|
+
This will create a +Product+ model, mapped to a *products* table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. So, suppose that the *products* table was created using an SQL sentence like:
|
80
82
|
|
81
83
|
<sql>
|
82
84
|
CREATE TABLE products (
|
@@ -99,12 +101,15 @@ h3. Overriding the Naming Conventions
|
|
99
101
|
What if you need to follow a different naming convention or need to use your Rails application with a legacy database? No problem, you can easily override the default conventions.
|
100
102
|
|
101
103
|
You can use the +ActiveRecord::Base.set_table_name+ method to specify the table name that should be used:
|
104
|
+
|
102
105
|
<ruby>
|
103
106
|
class Product < ActiveRecord::Base
|
104
107
|
set_table_name "PRODUCT"
|
105
108
|
end
|
106
109
|
</ruby>
|
110
|
+
|
107
111
|
If you do so, you will have to define manually the class name that is hosting the fixtures (class_name.yml) using the +set_fixture_class+ method in your test definition:
|
112
|
+
|
108
113
|
<ruby>
|
109
114
|
class FunnyJoke < ActiveSupport::TestCase
|
110
115
|
set_fixture_class :funny_jokes => 'Joke'
|
@@ -113,7 +118,8 @@ class FunnyJoke < ActiveSupport::TestCase
|
|
113
118
|
end
|
114
119
|
</ruby>
|
115
120
|
|
116
|
-
It's also possible to override the column that should be used as the table's primary key
|
121
|
+
It's also possible to override the column that should be used as the table's primary key using the +ActiveRecord::Base.set_primary_key+ method:
|
122
|
+
|
117
123
|
<ruby>
|
118
124
|
class Product < ActiveRecord::Base
|
119
125
|
set_primary_key "product_id"
|
@@ -122,7 +128,7 @@ end
|
|
122
128
|
|
123
129
|
h3. Reading and Writing Data
|
124
130
|
|
125
|
-
CRUD is an acronym for the four verbs we use to operate on data:
|
131
|
+
CRUD is an acronym for the four verbs we use to operate on data: *C*reate, *R*ead, *U*pdate and *D*elete. Active Record automatically creates methods to allow an application to read and manipulate data stored within its tables.
|
126
132
|
|
127
133
|
h4. Create
|
128
134
|
|
@@ -155,7 +161,7 @@ Finally, passing a block to either create or new will return a new User object:
|
|
155
161
|
|
156
162
|
h4. Read
|
157
163
|
|
158
|
-
|
164
|
+
Active Record provides a rich API for accessing data within a database. Below are a few examples of different data access methods provided by Active Record.
|
159
165
|
|
160
166
|
<ruby>
|
161
167
|
# return all records
|
@@ -163,7 +169,7 @@ ActiveRecord provides a rich API for accessing data within a database. Below are
|
|
163
169
|
</ruby>
|
164
170
|
|
165
171
|
<ruby>
|
166
|
-
# return first record
|
172
|
+
# return the first record
|
167
173
|
user = User.first
|
168
174
|
</ruby>
|
169
175
|
|
@@ -201,11 +207,11 @@ Likewise, once retrieved an Active Record object can be destroyed which removes
|
|
201
207
|
|
202
208
|
h3. Validations
|
203
209
|
|
204
|
-
Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format and many more. You can learn more about validations in the "Active Record Validations and Callbacks guide":
|
210
|
+
Active Record allows you to validate the state of a model before it gets written into the database. There are several methods that you can use to check your models and validate that an attribute value is not empty, is unique and not already in the database, follows a specific format and many more. You can learn more about validations in the "Active Record Validations and Callbacks guide":active_record_validations_callbacks.html#validations-overview.
|
205
211
|
|
206
212
|
h3. Callbacks
|
207
213
|
|
208
|
-
Active Record callbacks allow you to attach code to certain events in the life-cycle of your models. This enables you to add behavior to your models by transparently executing code when those events occur, like when you create a new record, update it, destroy it and so on. You can learn more about callbacks in the "Active Record Validations and Callbacks guide":
|
214
|
+
Active Record callbacks allow you to attach code to certain events in the life-cycle of your models. This enables you to add behavior to your models by transparently executing code when those events occur, like when you create a new record, update it, destroy it and so on. You can learn more about callbacks in the "Active Record Validations and Callbacks guide":active_record_validations_callbacks.html#callbacks-overview.
|
209
215
|
|
210
216
|
h3. Migrations
|
211
217
|
|
@@ -51,7 +51,7 @@ Active Record will perform queries on the database for you and is compatible wit
|
|
51
51
|
|
52
52
|
h3. Retrieving Objects from the Database
|
53
53
|
|
54
|
-
To retrieve objects from the database, Active Record provides several finder methods.
|
54
|
+
To retrieve objects from the database, Active Record provides several finder methods. Each finder method allows you to pass arguments into it to perform certain queries on your database without writing raw SQL.
|
55
55
|
|
56
56
|
The methods are:
|
57
57
|
* +where+
|
@@ -66,7 +66,7 @@ The methods are:
|
|
66
66
|
* +readonly+
|
67
67
|
* +from+
|
68
68
|
|
69
|
-
All of
|
69
|
+
All of the above methods return an instance of <tt>ActiveRecord::Relation</tt>.
|
70
70
|
|
71
71
|
Primary operation of <tt>Model.find(options)</tt> can be summarized as:
|
72
72
|
|
@@ -86,7 +86,7 @@ Using <tt>Model.find(primary_key)</tt>, you can retrieve the object correspondin
|
|
86
86
|
<ruby>
|
87
87
|
# Find the client with primary key (id) 10.
|
88
88
|
client = Client.find(10)
|
89
|
-
=> #<Client id: 10,
|
89
|
+
=> #<Client id: 10, first_name: => "Ryan">
|
90
90
|
</ruby>
|
91
91
|
|
92
92
|
SQL equivalent of the above is:
|
@@ -103,7 +103,7 @@ h5. +first+
|
|
103
103
|
|
104
104
|
<ruby>
|
105
105
|
client = Client.first
|
106
|
-
=> #<Client id: 1,
|
106
|
+
=> #<Client id: 1, first_name: => "Lifo">
|
107
107
|
</ruby>
|
108
108
|
|
109
109
|
SQL equivalent of the above is:
|
@@ -120,7 +120,7 @@ h5. +last+
|
|
120
120
|
|
121
121
|
<ruby>
|
122
122
|
client = Client.last
|
123
|
-
=> #<Client id: 221,
|
123
|
+
=> #<Client id: 221, first_name: => "Russel">
|
124
124
|
</ruby>
|
125
125
|
|
126
126
|
SQL equivalent of the above is:
|
@@ -140,7 +140,7 @@ h5. Using Multiple Primary Keys
|
|
140
140
|
<ruby>
|
141
141
|
# Find the clients with primary keys 1 and 10.
|
142
142
|
client = Client.find(1, 10) # Or even Client.find([1, 10])
|
143
|
-
=> [#<Client id: 1,
|
143
|
+
=> [#<Client id: 1, first_name: => "Lifo">, #<Client id: 10, first_name: => "Ryan">]
|
144
144
|
</ruby>
|
145
145
|
|
146
146
|
SQL equivalent of the above is:
|
@@ -227,7 +227,7 @@ h4. Pure String Conditions
|
|
227
227
|
|
228
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.
|
229
229
|
|
230
|
-
WARNING: Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. For example, +Client.where("
|
230
|
+
WARNING: Building your own conditions as pure strings can leave you vulnerable to SQL injection exploits. For example, +Client.where("first_name LIKE '%#{params[:first_name]}%'")+ is not safe. See the next section for the preferred way to handle conditions using an array.
|
231
231
|
|
232
232
|
h4. Array Conditions
|
233
233
|
|
@@ -337,7 +337,7 @@ Just like in Ruby. If you want a shorter syntax be sure to check out the "Hash C
|
|
337
337
|
|
338
338
|
h4. Hash Conditions
|
339
339
|
|
340
|
-
Active Record also allows you to pass in
|
340
|
+
Active Record also allows you to pass in hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want conditionalised and the values of how you want to conditionalise them:
|
341
341
|
|
342
342
|
NOTE: Only equality, range and subset checking are possible with Hash conditions.
|
343
343
|
|
@@ -347,7 +347,7 @@ h5. Equality Conditions
|
|
347
347
|
Client.where({ :locked => true })
|
348
348
|
</ruby>
|
349
349
|
|
350
|
-
The field name
|
350
|
+
The field name can also be a string:
|
351
351
|
|
352
352
|
<ruby>
|
353
353
|
Client.where({ 'locked' => true })
|
@@ -447,33 +447,33 @@ h4. Limit and Offset
|
|
447
447
|
|
448
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.
|
449
449
|
|
450
|
-
|
450
|
+
You can use +limit+ to specify the number of records to be retrieved, and use +offset+ to specify the number of records to skip before starting to return the records. For example
|
451
451
|
|
452
452
|
<ruby>
|
453
453
|
Client.limit(5)
|
454
454
|
</ruby>
|
455
455
|
|
456
|
-
|
456
|
+
will return a maximum of 5 clients and because it specifies no offset it will return the first 5 in the table. The SQL it executes looks like this:
|
457
457
|
|
458
458
|
<sql>
|
459
459
|
SELECT * FROM clients LIMIT 5
|
460
460
|
</sql>
|
461
461
|
|
462
|
-
|
462
|
+
Adding +offset+ to that
|
463
463
|
|
464
464
|
<ruby>
|
465
|
-
Client.limit(5).offset(
|
465
|
+
Client.limit(5).offset(30)
|
466
466
|
</ruby>
|
467
467
|
|
468
|
-
|
468
|
+
will return instead a maximum of 5 clients beginning with the 31st. The SQL looks like:
|
469
469
|
|
470
470
|
<sql>
|
471
|
-
SELECT * FROM clients LIMIT 5,
|
471
|
+
SELECT * FROM clients LIMIT 5, 30
|
472
472
|
</sql>
|
473
473
|
|
474
474
|
h4. Group
|
475
475
|
|
476
|
-
To apply +GROUP BY+ clause to the SQL fired by the finder, you can specify the +group+ method on the find.
|
476
|
+
To apply a +GROUP BY+ clause to the SQL fired by the finder, you can specify the +group+ method on the find.
|
477
477
|
|
478
478
|
For example, if you want to find a collection of the dates orders were created on:
|
479
479
|
|
@@ -491,7 +491,7 @@ SELECT * FROM orders GROUP BY date(created_at)
|
|
491
491
|
|
492
492
|
h4. Having
|
493
493
|
|
494
|
-
SQL uses +HAVING+ clause to specify conditions on the +GROUP BY+ fields. You can
|
494
|
+
SQL uses the +HAVING+ clause to specify conditions on the +GROUP BY+ fields. You can add the +HAVING+ clause to the SQL fired by the +Model.find+ by adding the +:having+ option to the find.
|
495
495
|
|
496
496
|
For example:
|
497
497
|
|
@@ -517,7 +517,7 @@ Any attempt to alter or destroy the readonly records will not succeed, raising a
|
|
517
517
|
Client.first.readonly(true)
|
518
518
|
</ruby>
|
519
519
|
|
520
|
-
|
520
|
+
For example, calling the following code will raise an +ActiveRecord::ReadOnlyRecord+ exception:
|
521
521
|
|
522
522
|
<ruby>
|
523
523
|
client = Client.first.readonly(true)
|
@@ -527,7 +527,9 @@ client.save
|
|
527
527
|
|
528
528
|
h4. Locking Records for Update
|
529
529
|
|
530
|
-
Locking is helpful for preventing
|
530
|
+
Locking is helpful for preventing race conditions when updating records in the database and ensuring atomic updates.
|
531
|
+
|
532
|
+
Active Record provides two locking mechanisms:
|
531
533
|
|
532
534
|
* Optimistic Locking
|
533
535
|
* Pessimistic Locking
|
@@ -538,13 +540,13 @@ Optimistic locking allows multiple users to access the same record for edits, an
|
|
538
540
|
|
539
541
|
<strong>Optimistic locking column</strong>
|
540
542
|
|
541
|
-
In order to use optimistic locking, the table needs to have a column called +lock_version+. Each time the record is updated, Active Record increments the +lock_version+ column
|
543
|
+
In order to use optimistic locking, the table needs to have a column called +lock_version+. Each time the record is updated, Active Record increments the +lock_version+ column. If an update request is made with a lower value in the +lock_version+ field than is currently in the +lock_version+ column in the database, the update request will fail with an +ActiveRecord::StaleObjectError+. Example:
|
542
544
|
|
543
545
|
<ruby>
|
544
546
|
c1 = Client.find(1)
|
545
547
|
c2 = Client.find(1)
|
546
548
|
|
547
|
-
c1.
|
549
|
+
c1.first_name = "Michael"
|
548
550
|
c1.save
|
549
551
|
|
550
552
|
c2.name = "should fail"
|
@@ -569,7 +571,7 @@ end
|
|
569
571
|
|
570
572
|
h5. Pessimistic Locking
|
571
573
|
|
572
|
-
Pessimistic locking uses locking mechanism provided by the underlying database. Passing +:lock => true+ to +Model.find+ obtains an exclusive lock on the selected rows. +Model.find+ using +:lock+ are usually wrapped inside a transaction for preventing deadlock conditions.
|
574
|
+
Pessimistic locking uses a locking mechanism provided by the underlying database. Passing +:lock => true+ to +Model.find+ obtains an exclusive lock on the selected rows. +Model.find+ using +:lock+ are usually wrapped inside a transaction for preventing deadlock conditions.
|
573
575
|
|
574
576
|
For example:
|
575
577
|
|
@@ -601,7 +603,7 @@ end
|
|
601
603
|
|
602
604
|
h3. Joining Tables
|
603
605
|
|
604
|
-
<tt>Model.find</tt> provides a +:joins+ option for specifying +JOIN+ clauses on the resulting SQL. There multiple
|
606
|
+
<tt>Model.find</tt> provides a +:joins+ option for specifying +JOIN+ clauses on the resulting SQL. There are multiple ways to specify the +:joins+ option:
|
605
607
|
|
606
608
|
h4. Using a String SQL Fragment
|
607
609
|
|
@@ -698,7 +700,7 @@ time_range = (Time.now.midnight - 1.day)..Time.now.midnight
|
|
698
700
|
Client.joins(:orders).where('orders.created_at' => time_range)
|
699
701
|
</ruby>
|
700
702
|
|
701
|
-
An alternative and cleaner syntax
|
703
|
+
An alternative and cleaner syntax is to nest the hash conditions:
|
702
704
|
|
703
705
|
<ruby>
|
704
706
|
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
|
@@ -727,7 +729,7 @@ This code looks fine at the first sight. But the problem lies within the total n
|
|
727
729
|
|
728
730
|
<strong>Solution to N <plus> 1 queries problem</strong>
|
729
731
|
|
730
|
-
Active Record lets you specify all the associations
|
732
|
+
Active Record lets you specify in advance all the associations 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 of the specified associations are loaded using the minimum possible number of queries.
|
731
733
|
|
732
734
|
Revisiting the above case, we could rewrite +Client.all+ to use eager load addresses:
|
733
735
|
|
@@ -749,7 +751,7 @@ SELECT addresses.* FROM addresses
|
|
749
751
|
|
750
752
|
h4. Eager Loading Multiple Associations
|
751
753
|
|
752
|
-
Active Record lets you eager load any
|
754
|
+
Active Record lets you eager load any 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.
|
753
755
|
|
754
756
|
h5. Array of Multiple Associations
|
755
757
|
|
@@ -765,7 +767,7 @@ h5. Nested Associations Hash
|
|
765
767
|
Category.find(1).includes(:posts => [{:comments => :guest}, :tags])
|
766
768
|
</ruby>
|
767
769
|
|
768
|
-
|
770
|
+
This will find the category with id 1 and eager load all of the associated posts, the associated posts' tags and comments, and every comment's guest association.
|
769
771
|
|
770
772
|
h4. Specifying Conditions on Eager Loaded Associations
|
771
773
|
|
@@ -773,32 +775,32 @@ Even though Active Record lets you specify conditions on the eager loaded associ
|
|
773
775
|
|
774
776
|
h3. Dynamic Finders
|
775
777
|
|
776
|
-
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called +
|
778
|
+
For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called +first_name+ on your +Client+ model for example, you get +find_by_first_name+ and +find_all_by_first_name+ for free from Active Record. If you have also have a +locked+ field on the +Client+ model, you also get +find_by_locked+ and +find_all_by_locked+.
|
777
779
|
|
778
780
|
You can do +find_last_by_*+ methods too which will find the last record matching your argument.
|
779
781
|
|
780
782
|
You can specify an exclamation point (<tt>!</tt>) on the end of the dynamic finders to get them to raise an +ActiveRecord::RecordNotFound+ error if they do not return any records, like +Client.find_by_name!("Ryan")+
|
781
783
|
|
782
|
-
If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields for example +Client.
|
784
|
+
If you want to find both by name and locked, you can chain these finders together by simply typing +and+ between the fields for example +Client.find_by_first_name_and_locked("Ryan", true)+.
|
783
785
|
|
784
786
|
|
785
|
-
There's another set of dynamic finders that let you find or create/initialize objects if they aren't found. These work in a similar fashion to the other finders and can be used like +
|
787
|
+
There's another set of dynamic finders that let you find or create/initialize objects if they aren't found. These work in a similar fashion to the other finders and can be used like +find_or_create_by_first_name(params[:first_name])+. Using this will first perform a find and then create if the find returns +nil+. The SQL looks like this for +Client.find_or_create_by_first_name("Ryan")+:
|
786
788
|
|
787
789
|
<sql>
|
788
|
-
SELECT * FROM clients WHERE (clients.
|
790
|
+
SELECT * FROM clients WHERE (clients.first_name = 'Ryan') LIMIT 1
|
789
791
|
BEGIN
|
790
|
-
INSERT INTO clients (
|
792
|
+
INSERT INTO clients (first_name, updated_at, created_at, orders_count, locked)
|
791
793
|
VALUES('Ryan', '2008-09-28 15:39:12', '2008-09-28 15:39:12', 0, '0')
|
792
794
|
COMMIT
|
793
795
|
</sql>
|
794
796
|
|
795
|
-
+find_or_create+'s sibling, +find_or_initialize+, will find an object and if it does not exist will act
|
797
|
+
+find_or_create+'s sibling, +find_or_initialize+, will find an object and if it does not exist will act similarly to calling +new+ with the arguments you passed in. For example:
|
796
798
|
|
797
799
|
<ruby>
|
798
|
-
client = Client.
|
800
|
+
client = Client.find_or_initialize_by_first_name('Ryan')
|
799
801
|
</ruby>
|
800
802
|
|
801
|
-
will either assign an existing client object with the name "Ryan" to the client local variable, or initialize a new object similar to calling +Client.new(:
|
803
|
+
will either assign an existing client object with the name "Ryan" to the client local variable, or initialize a new object similar to calling +Client.new(:first_name => 'Ryan')+. From here, you can modify other fields in client by calling the attribute setters on it: +client.locked = true+ and when you want to write it to the database just call +save+ on it.
|
802
804
|
|
803
805
|
h3. Finding by SQL
|
804
806
|
|
@@ -836,7 +838,7 @@ Client.exists?(1,2,3)
|
|
836
838
|
Client.exists?([1,2,3])
|
837
839
|
</ruby>
|
838
840
|
|
839
|
-
|
841
|
+
The +exists+ method may also take a +conditions+ option much like find:
|
840
842
|
|
841
843
|
<ruby>
|
842
844
|
Client.exists?(:conditions => "first_name = 'Ryan'")
|
@@ -869,7 +871,7 @@ SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
|
|
869
871
|
You can also use the +includes+ or +joins+ methods for this to do something a little more complex:
|
870
872
|
|
871
873
|
<ruby>
|
872
|
-
Client.
|
874
|
+
Client.where("clients.first_name = 'Ryan' AND orders.status = 'received'").includes("orders").count
|
873
875
|
</ruby>
|
874
876
|
|
875
877
|
Which will execute:
|