rails 4.0.0 → 4.2.11.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +30 -23
- data/guides/CHANGELOG.md +108 -6
- data/guides/Rakefile +21 -6
- data/guides/assets/images/akshaysurve.jpg +0 -0
- data/guides/assets/images/edge_badge.png +0 -0
- data/guides/assets/images/feature_tile.gif +0 -0
- data/guides/assets/images/footer_tile.gif +0 -0
- data/guides/assets/images/fxn.png +0 -0
- data/guides/assets/images/getting_started/article_with_comments.png +0 -0
- data/guides/assets/images/getting_started/challenge.png +0 -0
- data/guides/assets/images/getting_started/confirm_dialog.png +0 -0
- data/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +0 -0
- data/guides/assets/images/getting_started/form_with_errors.png +0 -0
- data/guides/assets/images/getting_started/index_action_with_edit_link.png +0 -0
- data/guides/assets/images/getting_started/new_article.png +0 -0
- data/guides/assets/images/getting_started/rails_welcome.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
- data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
- data/guides/assets/images/getting_started/show_action_for_articles.png +0 -0
- data/guides/assets/images/getting_started/template_is_missing_articles_new.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_articles.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_new_for_articles.png +0 -0
- data/guides/assets/images/header_tile.gif +0 -0
- data/guides/assets/images/icons/README +1 -1
- data/guides/assets/images/icons/callouts/11.png +0 -0
- data/guides/assets/images/icons/callouts/12.png +0 -0
- data/guides/assets/images/icons/callouts/13.png +0 -0
- data/guides/assets/images/icons/callouts/15.png +0 -0
- data/guides/assets/images/icons/caution.png +0 -0
- data/guides/assets/images/icons/example.png +0 -0
- data/guides/assets/images/radar.png +0 -0
- data/guides/assets/images/rails4_features.png +0 -0
- data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
- data/guides/assets/images/vijaydev.jpg +0 -0
- data/guides/assets/javascripts/guides.js +36 -34
- data/guides/assets/stylesheets/main.css +6 -2
- data/guides/assets/stylesheets/print.css +1 -1
- data/guides/bug_report_templates/action_controller_gem.rb +47 -0
- data/guides/bug_report_templates/action_controller_master.rb +54 -0
- data/guides/bug_report_templates/active_record_gem.rb +5 -2
- data/guides/bug_report_templates/active_record_master.rb +3 -2
- data/guides/bug_report_templates/generic_gem.rb +15 -0
- data/guides/bug_report_templates/generic_master.rb +26 -0
- data/guides/rails_guides.rb +23 -4
- data/guides/rails_guides/generator.rb +1 -1
- data/guides/rails_guides/helpers.rb +4 -2
- data/guides/rails_guides/levenshtein.rb +27 -21
- data/guides/rails_guides/markdown.rb +11 -7
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/source/2_2_release_notes.md +3 -3
- data/guides/source/2_3_release_notes.md +12 -12
- data/guides/source/3_0_release_notes.md +10 -13
- data/guides/source/3_1_release_notes.md +7 -4
- data/guides/source/3_2_release_notes.md +17 -14
- data/guides/source/4_0_release_notes.md +110 -54
- data/guides/source/4_1_release_notes.md +730 -0
- data/guides/source/4_2_release_notes.md +877 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +6 -2
- data/guides/source/action_controller_overview.md +223 -57
- data/guides/source/action_mailer_basics.md +129 -76
- data/guides/source/action_view_overview.md +247 -246
- data/guides/source/active_job_basics.md +339 -0
- data/guides/source/active_model_basics.md +374 -20
- data/guides/source/active_record_basics.md +46 -45
- data/guides/source/active_record_callbacks.md +83 -28
- data/guides/source/{migrations.md → active_record_migrations.md} +191 -275
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +382 -300
- data/guides/source/active_record_validations.md +64 -55
- data/guides/source/active_support_core_extensions.md +229 -187
- data/guides/source/active_support_instrumentation.md +23 -22
- data/guides/source/api_documentation_guidelines.md +167 -15
- data/guides/source/asset_pipeline.md +768 -294
- data/guides/source/association_basics.md +188 -96
- data/guides/source/autoloading_and_reloading_constants.md +1311 -0
- data/guides/source/caching_with_rails.md +45 -11
- data/guides/source/command_line.md +96 -65
- data/guides/source/configuring.md +404 -70
- data/guides/source/contributing_to_ruby_on_rails.md +270 -130
- data/guides/source/credits.html.erb +7 -3
- data/guides/source/debugging_rails_applications.md +471 -284
- data/guides/source/development_dependencies_install.md +115 -21
- data/guides/source/documents.yaml +31 -9
- data/guides/source/engines.md +737 -291
- data/guides/source/form_helpers.md +137 -89
- data/guides/source/generators.md +60 -28
- data/guides/source/getting_started.md +1007 -596
- data/guides/source/i18n.md +178 -96
- data/guides/source/index.html.erb +2 -1
- data/guides/source/initialization.md +248 -104
- data/guides/source/kindle/toc.html.erb +1 -1
- data/guides/source/layout.html.erb +14 -22
- data/guides/source/layouts_and_rendering.md +78 -46
- data/guides/source/maintenance_policy.md +78 -0
- data/guides/source/nested_model_forms.md +10 -7
- data/guides/source/plugins.md +66 -57
- data/guides/source/rails_application_templates.md +49 -12
- data/guides/source/rails_on_rack.md +50 -60
- data/guides/source/routing.md +190 -139
- data/guides/source/ruby_on_rails_guides_guidelines.md +12 -13
- data/guides/source/security.md +134 -83
- data/guides/source/testing.md +322 -200
- data/guides/source/upgrading_ruby_on_rails.md +834 -37
- data/guides/source/working_with_javascript_in_rails.md +36 -26
- data/guides/w3c_validator.rb +2 -0
- metadata +93 -116
- data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
- data/guides/assets/images/getting_started/new_post.png +0 -0
- data/guides/assets/images/getting_started/post_with_comments.png +0 -0
- data/guides/assets/images/getting_started/show_action_for_posts.png +0 -0
- data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
- data/guides/assets/images/getting_started/undefined_method_post_path.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
- data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
- data/guides/assets/images/jaimeiniesta.jpg +0 -0
- data/guides/code/getting_started/Gemfile +0 -43
- data/guides/code/getting_started/Gemfile.lock +0 -150
- data/guides/code/getting_started/README.rdoc +0 -28
- data/guides/code/getting_started/Rakefile +0 -6
- data/guides/code/getting_started/app/assets/javascripts/application.js +0 -16
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
- data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
- data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -17
- data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -47
- data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
- data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
- data/guides/code/getting_started/app/models/comment.rb +0 -3
- data/guides/code/getting_started/app/models/post.rb +0 -7
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
- data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
- data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
- data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
- data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
- data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
- data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -3
- data/guides/code/getting_started/bin/bundle +0 -4
- data/guides/code/getting_started/bin/rails +0 -4
- data/guides/code/getting_started/bin/rake +0 -4
- data/guides/code/getting_started/config.ru +0 -4
- data/guides/code/getting_started/config/application.rb +0 -18
- data/guides/code/getting_started/config/boot.rb +0 -4
- data/guides/code/getting_started/config/database.yml +0 -25
- data/guides/code/getting_started/config/environment.rb +0 -5
- data/guides/code/getting_started/config/environments/development.rb +0 -30
- data/guides/code/getting_started/config/environments/production.rb +0 -80
- data/guides/code/getting_started/config/environments/test.rb +0 -36
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
- data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
- data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
- data/guides/code/getting_started/config/initializers/locale.rb +0 -9
- data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
- data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
- data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
- data/guides/code/getting_started/config/locales/en.yml +0 -23
- data/guides/code/getting_started/config/routes.rb +0 -7
- data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
- data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
- data/guides/code/getting_started/db/schema.rb +0 -33
- data/guides/code/getting_started/db/seeds.rb +0 -7
- data/guides/code/getting_started/public/404.html +0 -58
- data/guides/code/getting_started/public/422.html +0 -58
- data/guides/code/getting_started/public/500.html +0 -57
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +0 -5
- data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
- data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
- data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
- data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
- data/guides/code/getting_started/test/models/comment_test.rb +0 -7
- data/guides/code/getting_started/test/models/post_test.rb +0 -7
- data/guides/code/getting_started/test/test_helper.rb +0 -15
- data/guides/source/kindle/KINDLE.md +0 -26
@@ -31,7 +31,7 @@ Object Relational Mapping system.
|
|
31
31
|
in his book _Patterns of Enterprise Application Architecture_. In
|
32
32
|
Active Record, objects carry both persistent data and behavior which
|
33
33
|
operates on that data. Active Record takes the opinion that ensuring
|
34
|
-
data access logic
|
34
|
+
data access logic as part of the object will educate users of that
|
35
35
|
object on how to write to and read from the database.
|
36
36
|
|
37
37
|
### Object Relational Mapping
|
@@ -48,10 +48,10 @@ overall database access code.
|
|
48
48
|
Active Record gives us several mechanisms, the most important being the ability
|
49
49
|
to:
|
50
50
|
|
51
|
-
* Represent models and their data
|
52
|
-
* Represent associations between these models
|
53
|
-
* Represent inheritance hierarchies through related models
|
54
|
-
* Validate models before they get persisted to the database
|
51
|
+
* Represent models and their data.
|
52
|
+
* Represent associations between these models.
|
53
|
+
* Represent inheritance hierarchies through related models.
|
54
|
+
* Validate models before they get persisted to the database.
|
55
55
|
* Perform database operations in an object-oriented fashion.
|
56
56
|
|
57
57
|
Convention over Configuration in Active Record
|
@@ -62,9 +62,9 @@ may be necessary to write a lot of configuration code. This is particularly true
|
|
62
62
|
for ORM frameworks in general. However, if you follow the conventions adopted by
|
63
63
|
Rails, you'll need to write very little configuration (in some case no
|
64
64
|
configuration at all) when creating Active Record models. The idea is that if
|
65
|
-
you configure your applications in the very same way most of the
|
66
|
-
should be the default way.
|
67
|
-
only in those cases where you can't follow the
|
65
|
+
you configure your applications in the very same way most of the time then this
|
66
|
+
should be the default way. Thus, explicit configuration would be needed
|
67
|
+
only in those cases where you can't follow the standard convention.
|
68
68
|
|
69
69
|
### Naming Conventions
|
70
70
|
|
@@ -78,17 +78,17 @@ of two or more words, the model class name should follow the Ruby conventions,
|
|
78
78
|
using the CamelCase form, while the table name must contain the words separated
|
79
79
|
by underscores. Examples:
|
80
80
|
|
81
|
-
* Database Table - Plural with underscores separating words (e.g., `book_clubs`)
|
81
|
+
* Database Table - Plural with underscores separating words (e.g., `book_clubs`).
|
82
82
|
* Model Class - Singular with the first letter of each word capitalized (e.g.,
|
83
|
-
`BookClub`)
|
83
|
+
`BookClub`).
|
84
84
|
|
85
|
-
| Model / Class
|
86
|
-
|
|
87
|
-
| `
|
88
|
-
| `LineItem`
|
89
|
-
| `Deer`
|
90
|
-
| `Mouse`
|
91
|
-
| `Person`
|
85
|
+
| Model / Class | Table / Schema |
|
86
|
+
| ---------------- | -------------- |
|
87
|
+
| `Article` | `articles` |
|
88
|
+
| `LineItem` | `line_items` |
|
89
|
+
| `Deer` | `deers` |
|
90
|
+
| `Mouse` | `mice` |
|
91
|
+
| `Person` | `people` |
|
92
92
|
|
93
93
|
|
94
94
|
### Schema Conventions
|
@@ -101,11 +101,11 @@ depending on the purpose of these columns.
|
|
101
101
|
fields that Active Record will look for when you create associations between
|
102
102
|
your models.
|
103
103
|
* **Primary keys** - By default, Active Record will use an integer column named
|
104
|
-
`id` as the table's primary key. When using [
|
104
|
+
`id` as the table's primary key. When using [Active Record
|
105
105
|
Migrations](migrations.html) to create your tables, this column will be
|
106
106
|
automatically created.
|
107
107
|
|
108
|
-
There are also some optional column names that will
|
108
|
+
There are also some optional column names that will add additional features
|
109
109
|
to Active Record instances:
|
110
110
|
|
111
111
|
* `created_at` - Automatically gets set to the current date and time when the
|
@@ -116,13 +116,13 @@ to Active Record instances:
|
|
116
116
|
locking](http://api.rubyonrails.org/classes/ActiveRecord/Locking.html) to
|
117
117
|
a model.
|
118
118
|
* `type` - Specifies that the model uses [Single Table
|
119
|
-
Inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html)
|
119
|
+
Inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#class-ActiveRecord::Base-label-Single+table+inheritance).
|
120
120
|
* `(association_name)_type` - Stores the type for
|
121
121
|
[polymorphic associations](association_basics.html#polymorphic-associations).
|
122
122
|
* `(table_name)_count` - Used to cache the number of belonging objects on
|
123
|
-
associations. For example, a `comments_count` column in a `
|
123
|
+
associations. For example, a `comments_count` column in a `Articles` class that
|
124
124
|
has many instances of `Comment` will cache the number of existent comments
|
125
|
-
for each
|
125
|
+
for each article.
|
126
126
|
|
127
127
|
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 (STI). If you are not using STI, try an analogous keyword like "context", that may still accurately describe the data you are modeling.
|
128
128
|
|
@@ -171,28 +171,28 @@ name that should be used:
|
|
171
171
|
|
172
172
|
```ruby
|
173
173
|
class Product < ActiveRecord::Base
|
174
|
-
self.table_name = "
|
174
|
+
self.table_name = "my_products"
|
175
175
|
end
|
176
176
|
```
|
177
177
|
|
178
178
|
If you do so, you will have to define manually the class name that is hosting
|
179
|
-
the fixtures (
|
179
|
+
the fixtures (my_products.yml) using the `set_fixture_class` method in your test
|
180
180
|
definition:
|
181
181
|
|
182
182
|
```ruby
|
183
|
-
class
|
184
|
-
set_fixture_class
|
185
|
-
fixtures :
|
183
|
+
class ProductTest < ActiveSupport::TestCase
|
184
|
+
set_fixture_class my_products: Product
|
185
|
+
fixtures :my_products
|
186
186
|
...
|
187
187
|
end
|
188
188
|
```
|
189
189
|
|
190
190
|
It's also possible to override the column that should be used as the table's
|
191
|
-
primary key using the `ActiveRecord::Base.
|
191
|
+
primary key using the `ActiveRecord::Base.primary_key=` method:
|
192
192
|
|
193
193
|
```ruby
|
194
194
|
class Product < ActiveRecord::Base
|
195
|
-
|
195
|
+
self.primary_key = "product_id"
|
196
196
|
end
|
197
197
|
```
|
198
198
|
|
@@ -253,12 +253,12 @@ user = User.first
|
|
253
253
|
|
254
254
|
```ruby
|
255
255
|
# return the first user named David
|
256
|
-
david = User.
|
256
|
+
david = User.find_by(name: 'David')
|
257
257
|
```
|
258
258
|
|
259
259
|
```ruby
|
260
260
|
# find all users named David who are Code Artists and sort by created_at in reverse chronological order
|
261
|
-
users = User.where(name: 'David', occupation: 'Code Artist').order(
|
261
|
+
users = User.where(name: 'David', occupation: 'Code Artist').order(created_at: :desc)
|
262
262
|
```
|
263
263
|
|
264
264
|
You can learn more about querying an Active Record model in the [Active Record
|
@@ -270,7 +270,7 @@ Once an Active Record object has been retrieved, its attributes can be modified
|
|
270
270
|
and it can be saved to the database.
|
271
271
|
|
272
272
|
```ruby
|
273
|
-
user = User.
|
273
|
+
user = User.find_by(name: 'David')
|
274
274
|
user.name = 'Dave'
|
275
275
|
user.save
|
276
276
|
```
|
@@ -279,7 +279,7 @@ A shorthand for this is to use a hash mapping attribute names to the desired
|
|
279
279
|
value, like so:
|
280
280
|
|
281
281
|
```ruby
|
282
|
-
user = User.
|
282
|
+
user = User.find_by(name: 'David')
|
283
283
|
user.update(name: 'Dave')
|
284
284
|
```
|
285
285
|
|
@@ -297,7 +297,7 @@ Likewise, once retrieved an Active Record object can be destroyed which removes
|
|
297
297
|
it from the database.
|
298
298
|
|
299
299
|
```ruby
|
300
|
-
user = User.
|
300
|
+
user = User.find_by(name: 'David')
|
301
301
|
user.destroy
|
302
302
|
```
|
303
303
|
|
@@ -309,11 +309,11 @@ into the database. There are several methods that you can use to check your
|
|
309
309
|
models and validate that an attribute value is not empty, is unique and not
|
310
310
|
already in the database, follows a specific format and many more.
|
311
311
|
|
312
|
-
Validation is a very important issue to consider when persisting to database, so
|
313
|
-
the methods `
|
312
|
+
Validation is a very important issue to consider when persisting to the database, so
|
313
|
+
the methods `save` and `update` take it into account when
|
314
314
|
running: they return `false` when validation fails and they didn't actually
|
315
|
-
perform any operation on database. All of these have a bang counterpart (that
|
316
|
-
is, `
|
315
|
+
perform any operation on the database. All of these have a bang counterpart (that
|
316
|
+
is, `save!` and `update!`), which are stricter in that
|
317
317
|
they raise the exception `ActiveRecord::RecordInvalid` if validation fails.
|
318
318
|
A quick example to illustrate:
|
319
319
|
|
@@ -322,8 +322,9 @@ class User < ActiveRecord::Base
|
|
322
322
|
validates :name, presence: true
|
323
323
|
end
|
324
324
|
|
325
|
-
User.
|
326
|
-
|
325
|
+
user = User.new
|
326
|
+
user.save # => false
|
327
|
+
user.save! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
327
328
|
```
|
328
329
|
|
329
330
|
You can learn more about validations in the [Active Record Validations
|
@@ -343,7 +344,7 @@ Migrations
|
|
343
344
|
|
344
345
|
Rails provides a domain-specific language for managing a database schema called
|
345
346
|
migrations. Migrations are stored in files which are executed against any
|
346
|
-
database that Active Record
|
347
|
+
database that Active Record supports using `rake`. Here's a migration that
|
347
348
|
creates a table:
|
348
349
|
|
349
350
|
```ruby
|
@@ -357,7 +358,7 @@ class CreatePublications < ActiveRecord::Migration
|
|
357
358
|
t.string :publisher_type
|
358
359
|
t.boolean :single_issue
|
359
360
|
|
360
|
-
t.timestamps
|
361
|
+
t.timestamps null: false
|
361
362
|
end
|
362
363
|
add_index :publications, :publication_type_id
|
363
364
|
end
|
@@ -368,6 +369,6 @@ Rails keeps track of which files have been committed to the database and
|
|
368
369
|
provides rollback features. To actually create the table, you'd run `rake db:migrate`
|
369
370
|
and to roll it back, `rake db:rollback`.
|
370
371
|
|
371
|
-
Note that the above code is database-agnostic: it will run in MySQL,
|
372
|
-
Oracle and others. You can learn more about migrations in the
|
373
|
-
Migrations guide](migrations.html)
|
372
|
+
Note that the above code is database-agnostic: it will run in MySQL,
|
373
|
+
PostgreSQL, Oracle and others. You can learn more about migrations in the
|
374
|
+
[Active Record Migrations guide](migrations.html).
|
@@ -15,7 +15,7 @@ After reading this guide, you will know:
|
|
15
15
|
The Object Life Cycle
|
16
16
|
---------------------
|
17
17
|
|
18
|
-
During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this
|
18
|
+
During the normal operation of a Rails application, objects may be created, updated, and destroyed. Active Record provides hooks into this *object life cycle* so that you can control your application and its data.
|
19
19
|
|
20
20
|
Callbacks allow you to trigger logic before or after an alteration of an object's state.
|
21
21
|
|
@@ -35,11 +35,11 @@ class User < ActiveRecord::Base
|
|
35
35
|
before_validation :ensure_login_has_a_value
|
36
36
|
|
37
37
|
protected
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
def ensure_login_has_a_value
|
39
|
+
if login.nil?
|
40
|
+
self.login = email unless email.blank?
|
41
|
+
end
|
41
42
|
end
|
42
|
-
end
|
43
43
|
end
|
44
44
|
```
|
45
45
|
|
@@ -49,13 +49,13 @@ The macro-style class methods can also receive a block. Consider using this styl
|
|
49
49
|
class User < ActiveRecord::Base
|
50
50
|
validates :login, :email, presence: true
|
51
51
|
|
52
|
-
before_create do
|
53
|
-
|
52
|
+
before_create do
|
53
|
+
self.name = login.capitalize if name.blank?
|
54
54
|
end
|
55
55
|
end
|
56
56
|
```
|
57
57
|
|
58
|
-
Callbacks can also be registered to only fire on certain
|
58
|
+
Callbacks can also be registered to only fire on certain life cycle events:
|
59
59
|
|
60
60
|
```ruby
|
61
61
|
class User < ActiveRecord::Base
|
@@ -65,13 +65,13 @@ class User < ActiveRecord::Base
|
|
65
65
|
after_validation :set_location, on: [ :create, :update ]
|
66
66
|
|
67
67
|
protected
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
def normalize_name
|
69
|
+
self.name = self.name.downcase.titleize
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
def set_location
|
73
|
+
self.location = LocationService.query(self)
|
74
|
+
end
|
75
75
|
end
|
76
76
|
```
|
77
77
|
|
@@ -92,6 +92,7 @@ Here is a list with all the available Active Record callbacks, listed in the sam
|
|
92
92
|
* `around_create`
|
93
93
|
* `after_create`
|
94
94
|
* `after_save`
|
95
|
+
* `after_commit/after_rollback`
|
95
96
|
|
96
97
|
### Updating an Object
|
97
98
|
|
@@ -103,12 +104,14 @@ Here is a list with all the available Active Record callbacks, listed in the sam
|
|
103
104
|
* `around_update`
|
104
105
|
* `after_update`
|
105
106
|
* `after_save`
|
107
|
+
* `after_commit/after_rollback`
|
106
108
|
|
107
109
|
### Destroying an Object
|
108
110
|
|
109
111
|
* `before_destroy`
|
110
112
|
* `around_destroy`
|
111
113
|
* `after_destroy`
|
114
|
+
* `after_commit/after_rollback`
|
112
115
|
|
113
116
|
WARNING. `after_save` runs both on create and update, but always _after_ the more specific callbacks `after_create` and `after_update`, no matter the order in which the macro calls were executed.
|
114
117
|
|
@@ -141,6 +144,55 @@ You have initialized an object!
|
|
141
144
|
=> #<User id: 1>
|
142
145
|
```
|
143
146
|
|
147
|
+
### `after_touch`
|
148
|
+
|
149
|
+
The `after_touch` callback will be called whenever an Active Record object is touched.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class User < ActiveRecord::Base
|
153
|
+
after_touch do |user|
|
154
|
+
puts "You have touched an object"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
>> u = User.create(name: 'Kuldeep')
|
159
|
+
=> #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49">
|
160
|
+
|
161
|
+
>> u.touch
|
162
|
+
You have touched an object
|
163
|
+
=> true
|
164
|
+
```
|
165
|
+
|
166
|
+
It can be used along with `belongs_to`:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
class Employee < ActiveRecord::Base
|
170
|
+
belongs_to :company, touch: true
|
171
|
+
after_touch do
|
172
|
+
puts 'An Employee was touched'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
class Company < ActiveRecord::Base
|
177
|
+
has_many :employees
|
178
|
+
after_touch :log_when_employees_or_company_touched
|
179
|
+
|
180
|
+
private
|
181
|
+
def log_when_employees_or_company_touched
|
182
|
+
puts 'Employee/Company was touched'
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
>> @employee = Employee.last
|
187
|
+
=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05">
|
188
|
+
|
189
|
+
# triggers @employee.company.touch
|
190
|
+
>> @employee.touch
|
191
|
+
Employee/Company was touched
|
192
|
+
An Employee was touched
|
193
|
+
=> true
|
194
|
+
```
|
195
|
+
|
144
196
|
Running Callbacks
|
145
197
|
-----------------
|
146
198
|
|
@@ -167,6 +219,7 @@ Additionally, the `after_find` callback is triggered by the following finder met
|
|
167
219
|
* `all`
|
168
220
|
* `first`
|
169
221
|
* `find`
|
222
|
+
* `find_by`
|
170
223
|
* `find_by_*`
|
171
224
|
* `find_by_*!`
|
172
225
|
* `find_by_sql`
|
@@ -179,7 +232,7 @@ NOTE: The `find_by_*` and `find_by_*!` methods are dynamic finders generated aut
|
|
179
232
|
Skipping Callbacks
|
180
233
|
------------------
|
181
234
|
|
182
|
-
Just as with validations, it is also possible to skip callbacks
|
235
|
+
Just as with validations, it is also possible to skip callbacks by using the following methods:
|
183
236
|
|
184
237
|
* `decrement`
|
185
238
|
* `decrement_counter`
|
@@ -194,6 +247,8 @@ Just as with validations, it is also possible to skip callbacks. These methods s
|
|
194
247
|
* `update_all`
|
195
248
|
* `update_counters`
|
196
249
|
|
250
|
+
These methods should be used with caution, however, because important business rules and application logic may be kept in callbacks. Bypassing them without understanding the potential implications may lead to invalid data.
|
251
|
+
|
197
252
|
Halting Execution
|
198
253
|
-----------------
|
199
254
|
|
@@ -201,32 +256,32 @@ As you start registering new callbacks for your models, they will be queued for
|
|
201
256
|
|
202
257
|
The whole callback chain is wrapped in a transaction. If any _before_ callback method returns exactly `false` or raises an exception, the execution chain gets halted and a ROLLBACK is issued; _after_ callbacks can only accomplish that by raising an exception.
|
203
258
|
|
204
|
-
WARNING.
|
259
|
+
WARNING. Any exception that is not `ActiveRecord::Rollback` will be re-raised by Rails after the callback chain is halted. Raising an exception other than `ActiveRecord::Rollback` may break code that does not expect methods like `save` and `update_attributes` (which normally try to return `true` or `false`) to raise an exception.
|
205
260
|
|
206
261
|
Relational Callbacks
|
207
262
|
--------------------
|
208
263
|
|
209
|
-
Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many
|
264
|
+
Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many articles. A user's articles should be destroyed if the user is destroyed. Let's add an `after_destroy` callback to the `User` model by way of its relationship to the `Article` model:
|
210
265
|
|
211
266
|
```ruby
|
212
267
|
class User < ActiveRecord::Base
|
213
|
-
has_many :
|
268
|
+
has_many :articles, dependent: :destroy
|
214
269
|
end
|
215
270
|
|
216
|
-
class
|
271
|
+
class Article < ActiveRecord::Base
|
217
272
|
after_destroy :log_destroy_action
|
218
273
|
|
219
274
|
def log_destroy_action
|
220
|
-
puts '
|
275
|
+
puts 'Article destroyed'
|
221
276
|
end
|
222
277
|
end
|
223
278
|
|
224
279
|
>> user = User.first
|
225
280
|
=> #<User id: 1>
|
226
|
-
>> user.
|
227
|
-
=> #<
|
281
|
+
>> user.articles.create!
|
282
|
+
=> #<Article id: 1, user_id: 1>
|
228
283
|
>> user.destroy
|
229
|
-
|
284
|
+
Article destroyed
|
230
285
|
=> #<User id: 1>
|
231
286
|
```
|
232
287
|
|
@@ -273,7 +328,7 @@ When writing conditional callbacks, it is possible to mix both `:if` and `:unles
|
|
273
328
|
```ruby
|
274
329
|
class Comment < ActiveRecord::Base
|
275
330
|
after_create :send_email_to_author, if: :author_wants_emails?,
|
276
|
-
unless: Proc.new { |comment| comment.
|
331
|
+
unless: Proc.new { |comment| comment.article.ignore_comments? }
|
277
332
|
end
|
278
333
|
```
|
279
334
|
|
@@ -287,7 +342,7 @@ Here's an example where we create a class with an `after_destroy` callback for a
|
|
287
342
|
```ruby
|
288
343
|
class PictureFileCallbacks
|
289
344
|
def after_destroy(picture_file)
|
290
|
-
if File.
|
345
|
+
if File.exist?(picture_file.filepath)
|
291
346
|
File.delete(picture_file.filepath)
|
292
347
|
end
|
293
348
|
end
|
@@ -307,7 +362,7 @@ Note that we needed to instantiate a new `PictureFileCallbacks` object, since we
|
|
307
362
|
```ruby
|
308
363
|
class PictureFileCallbacks
|
309
364
|
def self.after_destroy(picture_file)
|
310
|
-
if File.
|
365
|
+
if File.exist?(picture_file.filepath)
|
311
366
|
File.delete(picture_file.filepath)
|
312
367
|
end
|
313
368
|
end
|
@@ -342,7 +397,7 @@ By using the `after_commit` callback we can account for this case.
|
|
342
397
|
|
343
398
|
```ruby
|
344
399
|
class PictureFile < ActiveRecord::Base
|
345
|
-
after_commit :delete_picture_file_from_disk, :
|
400
|
+
after_commit :delete_picture_file_from_disk, on: [:destroy]
|
346
401
|
|
347
402
|
def delete_picture_file_from_disk
|
348
403
|
if File.exist?(filepath)
|
@@ -355,4 +410,4 @@ end
|
|
355
410
|
NOTE: the `:on` option specifies when a callback will be fired. If you
|
356
411
|
don't supply the `:on` option the callback will fire for every action.
|
357
412
|
|
358
|
-
The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback.
|
413
|
+
WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback.
|