rails 4.0.13 → 4.1.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -17
- data/guides/CHANGELOG.md +68 -34
- 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 +30 -34
- data/guides/assets/stylesheets/main.css +2 -1
- data/guides/assets/stylesheets/print.css +1 -1
- data/guides/bug_report_templates/action_controller_gem.rb +9 -4
- data/guides/bug_report_templates/action_controller_master.rb +4 -2
- data/guides/bug_report_templates/active_record_gem.rb +5 -2
- data/guides/bug_report_templates/active_record_master.rb +2 -1
- data/guides/bug_report_templates/generic_gem.rb +15 -0
- data/guides/bug_report_templates/generic_master.rb +26 -0
- data/guides/code/getting_started/Gemfile +21 -24
- data/guides/code/getting_started/Gemfile.lock +78 -73
- data/guides/code/getting_started/Rakefile +1 -1
- data/guides/code/getting_started/app/assets/javascripts/application.js +1 -2
- data/guides/code/getting_started/app/views/layouts/application.html.erb +2 -2
- data/guides/code/getting_started/config/environment.rb +1 -1
- data/guides/code/getting_started/config/environments/development.rb +2 -2
- data/guides/code/getting_started/config/environments/production.rb +3 -3
- data/guides/code/getting_started/config/environments/test.rb +2 -2
- data/guides/code/getting_started/config/initializers/secret_token.rb +1 -1
- data/guides/code/getting_started/config/initializers/session_store.rb +1 -1
- data/guides/code/getting_started/config/routes.rb +1 -1
- data/guides/code/getting_started/config.ru +1 -1
- data/guides/code/getting_started/public/404.html +2 -0
- data/guides/code/getting_started/public/422.html +2 -0
- data/guides/code/getting_started/public/500.html +2 -0
- data/guides/code/getting_started/test/test_helper.rb +0 -3
- data/guides/rails_guides/helpers.rb +3 -1
- data/guides/source/2_2_release_notes.md +2 -2
- data/guides/source/2_3_release_notes.md +8 -8
- data/guides/source/3_0_release_notes.md +2 -3
- data/guides/source/3_1_release_notes.md +2 -2
- data/guides/source/3_2_release_notes.md +12 -12
- data/guides/source/4_0_release_notes.md +79 -46
- data/guides/source/4_1_release_notes.md +731 -0
- data/guides/source/_welcome.html.erb +5 -2
- data/guides/source/action_controller_overview.md +189 -40
- data/guides/source/action_mailer_basics.md +27 -27
- data/guides/source/action_view_overview.md +131 -20
- data/guides/source/active_model_basics.md +6 -6
- data/guides/source/active_record_basics.md +15 -15
- data/guides/source/active_record_callbacks.md +18 -16
- data/guides/source/active_record_querying.md +93 -51
- data/guides/source/active_record_validations.md +26 -24
- data/guides/source/active_support_core_extensions.md +72 -118
- data/guides/source/active_support_instrumentation.md +13 -4
- data/guides/source/api_documentation_guidelines.md +104 -6
- data/guides/source/asset_pipeline.md +573 -244
- data/guides/source/association_basics.md +94 -22
- data/guides/source/caching_with_rails.md +15 -6
- data/guides/source/command_line.md +55 -46
- data/guides/source/configuring.md +248 -52
- data/guides/source/contributing_to_ruby_on_rails.md +18 -17
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +39 -8
- data/guides/source/development_dependencies_install.md +91 -8
- data/guides/source/documents.yaml +4 -0
- data/guides/source/engines.md +678 -232
- data/guides/source/form_helpers.md +53 -35
- data/guides/source/generators.md +19 -15
- data/guides/source/getting_started.md +758 -497
- data/guides/source/i18n.md +64 -28
- data/guides/source/index.html.erb +1 -1
- data/guides/source/initialization.md +155 -58
- data/guides/source/kindle/toc.html.erb +1 -1
- data/guides/source/layout.html.erb +2 -2
- data/guides/source/layouts_and_rendering.md +59 -26
- data/guides/source/maintenance_policy.md +3 -3
- data/guides/source/migrations.md +101 -62
- data/guides/source/nested_model_forms.md +3 -3
- data/guides/source/plugins.md +34 -31
- data/guides/source/rails_application_templates.md +27 -8
- data/guides/source/rails_on_rack.md +41 -58
- data/guides/source/routing.md +115 -104
- data/guides/source/ruby_on_rails_guides_guidelines.md +2 -2
- data/guides/source/security.md +81 -36
- data/guides/source/testing.md +56 -79
- data/guides/source/upgrading_ruby_on_rails.md +531 -21
- data/guides/source/working_with_javascript_in_rails.md +19 -11
- metadata +51 -23
- 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/source/kindle/KINDLE.md +0 -26
@@ -58,6 +58,7 @@ The methods are:
|
|
58
58
|
|
59
59
|
* `bind`
|
60
60
|
* `create_with`
|
61
|
+
* `distinct`
|
61
62
|
* `eager_load`
|
62
63
|
* `extending`
|
63
64
|
* `from`
|
@@ -76,7 +77,6 @@ The methods are:
|
|
76
77
|
* `reorder`
|
77
78
|
* `reverse_order`
|
78
79
|
* `select`
|
79
|
-
* `distinct`
|
80
80
|
* `uniq`
|
81
81
|
* `where`
|
82
82
|
|
@@ -91,7 +91,7 @@ The primary operation of `Model.find(options)` can be summarized as:
|
|
91
91
|
|
92
92
|
### Retrieving a Single Object
|
93
93
|
|
94
|
-
Active Record provides
|
94
|
+
Active Record provides several different ways of retrieving a single object.
|
95
95
|
|
96
96
|
#### Using a Primary Key
|
97
97
|
|
@@ -473,7 +473,7 @@ In the case of a belongs_to relationship, an association key can be used to spec
|
|
473
473
|
|
474
474
|
```ruby
|
475
475
|
Post.where(author: author)
|
476
|
-
Author.joins(:posts).where(posts: {author: author})
|
476
|
+
Author.joins(:posts).where(posts: { author: author })
|
477
477
|
```
|
478
478
|
|
479
479
|
NOTE: The values cannot be symbols. For example, you cannot do `Client.where(status: :active)`.
|
@@ -685,9 +685,9 @@ This will return single order objects for each day, but only those that are orde
|
|
685
685
|
Overriding Conditions
|
686
686
|
---------------------
|
687
687
|
|
688
|
-
### `
|
688
|
+
### `unscope`
|
689
689
|
|
690
|
-
You can specify certain conditions to be
|
690
|
+
You can specify certain conditions to be removed using the `unscope` method. For example:
|
691
691
|
|
692
692
|
```ruby
|
693
693
|
Post.where('id > 10').limit(20).order('id asc').except(:order)
|
@@ -697,27 +697,25 @@ The SQL that would be executed:
|
|
697
697
|
|
698
698
|
```sql
|
699
699
|
SELECT * FROM posts WHERE id > 10 LIMIT 20
|
700
|
-
```
|
701
700
|
|
702
|
-
|
701
|
+
# Original query without `unscope`
|
702
|
+
SELECT * FROM posts WHERE id > 10 ORDER BY id asc LIMIT 20
|
703
703
|
|
704
|
-
The `except` method does not work when the relation is merged. For example:
|
705
|
-
|
706
|
-
```ruby
|
707
|
-
Post.comments.except(:order)
|
708
704
|
```
|
709
705
|
|
710
|
-
|
706
|
+
You can additionally unscope specific where clauses. For example:
|
711
707
|
|
712
708
|
```ruby
|
713
|
-
Post.
|
714
|
-
|
709
|
+
Post.where(id: 10, trashed: false).unscope(where: :id)
|
710
|
+
# SELECT "posts".* FROM "posts" WHERE trashed = 0
|
715
711
|
```
|
716
712
|
|
717
|
-
|
713
|
+
A relation which has used `unscope` will affect any relation it is
|
714
|
+
merged in to:
|
718
715
|
|
719
716
|
```ruby
|
720
|
-
Post.
|
717
|
+
Post.order('id asc').merge(Post.unscope(:order))
|
718
|
+
# SELECT "posts".* FROM "posts"
|
721
719
|
```
|
722
720
|
|
723
721
|
### `only`
|
@@ -732,6 +730,10 @@ The SQL that would be executed:
|
|
732
730
|
|
733
731
|
```sql
|
734
732
|
SELECT * FROM posts WHERE id > 10 ORDER BY id DESC
|
733
|
+
|
734
|
+
# Original query without `only`
|
735
|
+
SELECT "posts".* FROM "posts" WHERE (id > 10) ORDER BY id desc LIMIT 20
|
736
|
+
|
735
737
|
```
|
736
738
|
|
737
739
|
### `reorder`
|
@@ -742,7 +744,7 @@ The `reorder` method overrides the default scope order. For example:
|
|
742
744
|
class Post < ActiveRecord::Base
|
743
745
|
..
|
744
746
|
..
|
745
|
-
has_many :comments, order
|
747
|
+
has_many :comments, -> { order('posted_at DESC') }
|
746
748
|
end
|
747
749
|
|
748
750
|
Post.find(10).comments.reorder('name')
|
@@ -751,13 +753,15 @@ Post.find(10).comments.reorder('name')
|
|
751
753
|
The SQL that would be executed:
|
752
754
|
|
753
755
|
```sql
|
754
|
-
SELECT * FROM posts WHERE id = 10
|
756
|
+
SELECT * FROM posts WHERE id = 10
|
757
|
+
SELECT * FROM comments WHERE post_id = 10 ORDER BY name
|
755
758
|
```
|
756
759
|
|
757
760
|
In case the `reorder` clause is not used, the SQL executed would be:
|
758
761
|
|
759
762
|
```sql
|
760
|
-
SELECT * FROM posts WHERE id = 10
|
763
|
+
SELECT * FROM posts WHERE id = 10
|
764
|
+
SELECT * FROM comments WHERE post_id = 10 ORDER BY posted_at DESC
|
761
765
|
```
|
762
766
|
|
763
767
|
### `reverse_order`
|
@@ -788,6 +792,32 @@ SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
|
|
788
792
|
|
789
793
|
This method accepts **no** arguments.
|
790
794
|
|
795
|
+
### `rewhere`
|
796
|
+
|
797
|
+
The `rewhere` method overrides an existing, named where condition. For example:
|
798
|
+
|
799
|
+
```ruby
|
800
|
+
Post.where(trashed: true).rewhere(trashed: false)
|
801
|
+
```
|
802
|
+
|
803
|
+
The SQL that would be executed:
|
804
|
+
|
805
|
+
```sql
|
806
|
+
SELECT * FROM posts WHERE `trashed` = 0
|
807
|
+
```
|
808
|
+
|
809
|
+
In case the `rewhere` clause is not used,
|
810
|
+
|
811
|
+
```ruby
|
812
|
+
Post.where(trashed: true).where(trashed: false)
|
813
|
+
```
|
814
|
+
|
815
|
+
the SQL executed would be:
|
816
|
+
|
817
|
+
```sql
|
818
|
+
SELECT * FROM posts WHERE `trashed` = 1 AND `trashed` = 0
|
819
|
+
```
|
820
|
+
|
791
821
|
Null Relation
|
792
822
|
-------------
|
793
823
|
|
@@ -826,8 +856,6 @@ client.save
|
|
826
856
|
|
827
857
|
As `client` is explicitly set to be a readonly object, the above code will raise an `ActiveRecord::ReadOnlyRecord` exception when calling `client.save` with an updated value of _visits_.
|
828
858
|
|
829
|
-
NOTE: using `joins` without an explicit `select` will return readonly records.
|
830
|
-
|
831
859
|
Locking Records for Update
|
832
860
|
--------------------------
|
833
861
|
|
@@ -931,15 +959,13 @@ This will result in the following SQL:
|
|
931
959
|
SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id
|
932
960
|
```
|
933
961
|
|
934
|
-
NOTE: using `joins` might return readonly records. See [readonly](active_record_querying.html#readonly-objects) for more details.
|
935
|
-
|
936
962
|
### Using Array/Hash of Named Associations
|
937
963
|
|
938
964
|
WARNING: This method only works with `INNER JOIN`.
|
939
965
|
|
940
966
|
Active Record lets you use the names of the [associations](association_basics.html) defined on the model as a shortcut for specifying `JOIN` clause for those associations when using the `joins` method.
|
941
967
|
|
942
|
-
For example, consider the following `Category`, `Post`, `
|
968
|
+
For example, consider the following `Category`, `Post`, `Comment`, `Guest` and `Tag` models:
|
943
969
|
|
944
970
|
```ruby
|
945
971
|
class Category < ActiveRecord::Base
|
@@ -1018,7 +1044,7 @@ Or, in English: "return all posts that have a comment made by a guest."
|
|
1018
1044
|
#### Joining Nested Associations (Multiple Level)
|
1019
1045
|
|
1020
1046
|
```ruby
|
1021
|
-
Category.joins(posts: [{comments: :guest}, :tags])
|
1047
|
+
Category.joins(posts: [{ comments: :guest }, :tags])
|
1022
1048
|
```
|
1023
1049
|
|
1024
1050
|
This produces:
|
@@ -1044,7 +1070,7 @@ An alternative and cleaner syntax is to nest the hash conditions:
|
|
1044
1070
|
|
1045
1071
|
```ruby
|
1046
1072
|
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
|
1047
|
-
Client.joins(:orders).where(orders: {created_at: time_range})
|
1073
|
+
Client.joins(:orders).where(orders: { created_at: time_range })
|
1048
1074
|
```
|
1049
1075
|
|
1050
1076
|
This will find all clients who have orders that were created yesterday, again using a `BETWEEN` SQL expression.
|
@@ -1105,7 +1131,7 @@ This loads all the posts and the associated category and comments for each post.
|
|
1105
1131
|
#### Nested Associations Hash
|
1106
1132
|
|
1107
1133
|
```ruby
|
1108
|
-
Category.includes(posts: [{comments: :guest}, :tags]).find(1)
|
1134
|
+
Category.includes(posts: [{ comments: :guest }, :tags]).find(1)
|
1109
1135
|
```
|
1110
1136
|
|
1111
1137
|
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.
|
@@ -1117,18 +1143,30 @@ Even though Active Record lets you specify conditions on the eager loaded associ
|
|
1117
1143
|
However if you must do this, you may use `where` as you would normally.
|
1118
1144
|
|
1119
1145
|
```ruby
|
1120
|
-
Post.includes(:comments).where(
|
1146
|
+
Post.includes(:comments).where(comments: { visible: true })
|
1121
1147
|
```
|
1122
1148
|
|
1123
|
-
This would generate a query which contains a `LEFT OUTER JOIN` whereas the
|
1149
|
+
This would generate a query which contains a `LEFT OUTER JOIN` whereas the
|
1150
|
+
`joins` method would generate one using the `INNER JOIN` function instead.
|
1124
1151
|
|
1125
1152
|
```ruby
|
1126
1153
|
SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)
|
1127
1154
|
```
|
1128
1155
|
|
1129
|
-
If there was no `where` condition, this would generate the normal set of two
|
1156
|
+
If there was no `where` condition, this would generate the normal set of two
|
1157
|
+
queries.
|
1158
|
+
|
1159
|
+
NOTE: Using `where` like this will only work when you pass it a Hash. For
|
1160
|
+
SQL-fragments you need use `references` to force joined tables:
|
1161
|
+
|
1162
|
+
```ruby
|
1163
|
+
Post.includes(:comments).where("comments.visible = true").references(:comments)
|
1164
|
+
```
|
1165
|
+
|
1166
|
+
If, in the case of this `includes` query, there were no comments for any posts,
|
1167
|
+
all the posts would still be loaded. By using `joins` (an INNER JOIN), the join
|
1168
|
+
conditions **must** match, otherwise no records will be returned.
|
1130
1169
|
|
1131
|
-
If, in the case of this `includes` query, there were no comments for any posts, all the posts would still be loaded. By using `joins` (an INNER JOIN), the join conditions **must** match, otherwise no records will be returned.
|
1132
1170
|
|
1133
1171
|
Scopes
|
1134
1172
|
------
|
@@ -1185,7 +1223,7 @@ class Post < ActiveRecord::Base
|
|
1185
1223
|
end
|
1186
1224
|
```
|
1187
1225
|
|
1188
|
-
|
1226
|
+
Call the scope as if it were a class method:
|
1189
1227
|
|
1190
1228
|
```ruby
|
1191
1229
|
Post.created_before(Time.zone.now)
|
@@ -1218,46 +1256,46 @@ class User < ActiveRecord::Base
|
|
1218
1256
|
end
|
1219
1257
|
|
1220
1258
|
User.active.inactive
|
1221
|
-
#
|
1259
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'inactive'
|
1222
1260
|
```
|
1223
1261
|
|
1224
1262
|
We can mix and match `scope` and `where` conditions and the final sql
|
1225
|
-
will have all conditions joined with `AND
|
1263
|
+
will have all conditions joined with `AND`.
|
1226
1264
|
|
1227
1265
|
```ruby
|
1228
1266
|
User.active.where(state: 'finished')
|
1229
|
-
#
|
1267
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'finished'
|
1230
1268
|
```
|
1231
1269
|
|
1232
1270
|
If we do want the `last where clause` to win then `Relation#merge` can
|
1233
|
-
be used
|
1271
|
+
be used.
|
1234
1272
|
|
1235
1273
|
```ruby
|
1236
1274
|
User.active.merge(User.inactive)
|
1237
|
-
#
|
1275
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'
|
1238
1276
|
```
|
1239
1277
|
|
1240
|
-
One important caveat is that `default_scope` will be
|
1278
|
+
One important caveat is that `default_scope` will be prepended in
|
1241
1279
|
`scope` and `where` conditions.
|
1242
1280
|
|
1243
1281
|
```ruby
|
1244
1282
|
class User < ActiveRecord::Base
|
1245
|
-
default_scope
|
1283
|
+
default_scope { where state: 'pending' }
|
1246
1284
|
scope :active, -> { where state: 'active' }
|
1247
1285
|
scope :inactive, -> { where state: 'inactive' }
|
1248
1286
|
end
|
1249
1287
|
|
1250
1288
|
User.all
|
1251
|
-
#
|
1289
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'
|
1252
1290
|
|
1253
1291
|
User.active
|
1254
|
-
#
|
1292
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'
|
1255
1293
|
|
1256
1294
|
User.where(state: 'inactive')
|
1257
|
-
#
|
1295
|
+
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'
|
1258
1296
|
```
|
1259
1297
|
|
1260
|
-
As you can see above the `default_scope` is being
|
1298
|
+
As you can see above the `default_scope` is being merged in both
|
1261
1299
|
`scope` and `where` conditions.
|
1262
1300
|
|
1263
1301
|
|
@@ -1354,7 +1392,7 @@ COMMIT
|
|
1354
1392
|
|
1355
1393
|
The new record might not be saved to the database; that depends on whether validations passed or not (just like `create`).
|
1356
1394
|
|
1357
|
-
Suppose we want to set the 'locked' attribute to
|
1395
|
+
Suppose we want to set the 'locked' attribute to `false` if we're
|
1358
1396
|
creating a new record, but we don't want to include it in the query. So
|
1359
1397
|
we want to find the client named "Andy", or if that client doesn't
|
1360
1398
|
exist, create a client named "Andy" which is not locked.
|
@@ -1431,7 +1469,7 @@ If you'd like to use your own SQL to find records in a table you can use `find_b
|
|
1431
1469
|
```ruby
|
1432
1470
|
Client.find_by_sql("SELECT * FROM clients
|
1433
1471
|
INNER JOIN orders ON clients.id = orders.client_id
|
1434
|
-
ORDER clients.created_at desc")
|
1472
|
+
ORDER BY clients.created_at desc")
|
1435
1473
|
```
|
1436
1474
|
|
1437
1475
|
`find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects.
|
@@ -1532,18 +1570,21 @@ Person.ids
|
|
1532
1570
|
Existence of Objects
|
1533
1571
|
--------------------
|
1534
1572
|
|
1535
|
-
If you simply want to check for the existence of the object there's a method called `exists?`.
|
1573
|
+
If you simply want to check for the existence of the object there's a method called `exists?`.
|
1574
|
+
This method will query the database using the same query as `find`, but instead of returning an
|
1575
|
+
object or collection of objects it will return either `true` or `false`.
|
1536
1576
|
|
1537
1577
|
```ruby
|
1538
1578
|
Client.exists?(1)
|
1539
1579
|
```
|
1540
1580
|
|
1541
|
-
The `exists?` method also takes multiple
|
1581
|
+
The `exists?` method also takes multiple values, but the catch is that it will return `true` if any
|
1582
|
+
one of those records exists.
|
1542
1583
|
|
1543
1584
|
```ruby
|
1544
|
-
Client.exists?(1,2,3)
|
1585
|
+
Client.exists?(id: [1,2,3])
|
1545
1586
|
# or
|
1546
|
-
Client.exists?([
|
1587
|
+
Client.exists?(name: ['John', 'Sergei'])
|
1547
1588
|
```
|
1548
1589
|
|
1549
1590
|
It's even possible to use `exists?` without any arguments on a model or a relation.
|
@@ -1552,7 +1593,8 @@ It's even possible to use `exists?` without any arguments on a model or a relati
|
|
1552
1593
|
Client.where(first_name: 'Ryan').exists?
|
1553
1594
|
```
|
1554
1595
|
|
1555
|
-
The above returns `true` if there is at least one client with the `first_name` 'Ryan' and `false`
|
1596
|
+
The above returns `true` if there is at least one client with the `first_name` 'Ryan' and `false`
|
1597
|
+
otherwise.
|
1556
1598
|
|
1557
1599
|
```ruby
|
1558
1600
|
Client.exists?
|
@@ -1602,7 +1644,7 @@ Client.where(first_name: 'Ryan').count
|
|
1602
1644
|
You can also use various finder methods on a relation for performing complex calculations:
|
1603
1645
|
|
1604
1646
|
```ruby
|
1605
|
-
Client.includes("orders").where(first_name: 'Ryan', orders: {status: 'received'}).count
|
1647
|
+
Client.includes("orders").where(first_name: 'Ryan', orders: { status: 'received' }).count
|
1606
1648
|
```
|
1607
1649
|
|
1608
1650
|
Which will execute:
|
@@ -85,7 +85,7 @@ end
|
|
85
85
|
We can see how it works by looking at some `rails console` output:
|
86
86
|
|
87
87
|
```ruby
|
88
|
-
$ rails console
|
88
|
+
$ bin/rails console
|
89
89
|
>> p = Person.new(name: "John Doe")
|
90
90
|
=> #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil>
|
91
91
|
>> p.new_record?
|
@@ -162,8 +162,8 @@ Person.create(name: nil).valid? # => false
|
|
162
162
|
```
|
163
163
|
|
164
164
|
After Active Record has performed validations, any errors found can be accessed
|
165
|
-
through the `errors` instance method, which returns a collection of errors.
|
166
|
-
definition, an object is valid if this collection is empty after running
|
165
|
+
through the `errors.messages` instance method, which returns a collection of errors.
|
166
|
+
By definition, an object is valid if this collection is empty after running
|
167
167
|
validations.
|
168
168
|
|
169
169
|
Note that an object instantiated with `new` will not report errors even if it's
|
@@ -175,28 +175,28 @@ class Person < ActiveRecord::Base
|
|
175
175
|
end
|
176
176
|
|
177
177
|
>> p = Person.new
|
178
|
-
|
179
|
-
>> p.errors
|
180
|
-
|
178
|
+
# => #<Person id: nil, name: nil>
|
179
|
+
>> p.errors.messages
|
180
|
+
# => {}
|
181
181
|
|
182
182
|
>> p.valid?
|
183
|
-
|
184
|
-
>> p.errors
|
185
|
-
|
183
|
+
# => false
|
184
|
+
>> p.errors.messages
|
185
|
+
# => {name:["can't be blank"]}
|
186
186
|
|
187
187
|
>> p = Person.create
|
188
|
-
|
189
|
-
>> p.errors
|
190
|
-
|
188
|
+
# => #<Person id: nil, name: nil>
|
189
|
+
>> p.errors.messages
|
190
|
+
# => {name:["can't be blank"]}
|
191
191
|
|
192
192
|
>> p.save
|
193
|
-
|
193
|
+
# => false
|
194
194
|
|
195
195
|
>> p.save!
|
196
|
-
|
196
|
+
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
197
197
|
|
198
198
|
>> Person.create!
|
199
|
-
|
199
|
+
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
200
200
|
```
|
201
201
|
|
202
202
|
`invalid?` is simply the inverse of `valid?`. It triggers your validations,
|
@@ -357,7 +357,7 @@ given regular expression, which is specified using the `:with` option.
|
|
357
357
|
```ruby
|
358
358
|
class Product < ActiveRecord::Base
|
359
359
|
validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/,
|
360
|
-
message: "
|
360
|
+
message: "only allows letters" }
|
361
361
|
end
|
362
362
|
```
|
363
363
|
|
@@ -526,7 +526,7 @@ If you validate the presence of an object associated via a `has_one` or
|
|
526
526
|
Since `false.blank?` is true, if you want to validate the presence of a boolean
|
527
527
|
field you should use `validates :field_name, inclusion: { in: [true, false] }`.
|
528
528
|
|
529
|
-
The default error message is _"can't be
|
529
|
+
The default error message is _"can't be blank"_.
|
530
530
|
|
531
531
|
### `absence`
|
532
532
|
|
@@ -575,7 +575,9 @@ This helper validates that the attribute's value is unique right before the
|
|
575
575
|
object gets saved. It does not create a uniqueness constraint in the database,
|
576
576
|
so it may happen that two different database connections create two records
|
577
577
|
with the same value for a column that you intend to be unique. To avoid that,
|
578
|
-
you must create a unique index in your database.
|
578
|
+
you must create a unique index on both columns in your database. See
|
579
|
+
[the MySQL manual](http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html)
|
580
|
+
for more details about multiple column indexes.
|
579
581
|
|
580
582
|
```ruby
|
581
583
|
class Account < ActiveRecord::Base
|
@@ -682,7 +684,7 @@ class GoodnessValidator
|
|
682
684
|
end
|
683
685
|
end
|
684
686
|
|
685
|
-
#
|
687
|
+
# ...
|
686
688
|
end
|
687
689
|
```
|
688
690
|
|
@@ -734,8 +736,8 @@ class Topic < ActiveRecord::Base
|
|
734
736
|
validates :title, length: { is: 5 }, allow_blank: true
|
735
737
|
end
|
736
738
|
|
737
|
-
Topic.create(
|
738
|
-
Topic.create(
|
739
|
+
Topic.create(title: "").valid? # => true
|
740
|
+
Topic.create(title: nil).valid? # => true
|
739
741
|
```
|
740
742
|
|
741
743
|
### `:message`
|
@@ -781,7 +783,7 @@ end
|
|
781
783
|
Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank
|
782
784
|
```
|
783
785
|
|
784
|
-
There is also an ability to pass custom exception to `:strict` option
|
786
|
+
There is also an ability to pass custom exception to `:strict` option.
|
785
787
|
|
786
788
|
```ruby
|
787
789
|
class Person < ActiveRecord::Base
|
@@ -990,12 +992,12 @@ end
|
|
990
992
|
|
991
993
|
person = Person.new
|
992
994
|
person.valid? # => false
|
993
|
-
person.errors
|
995
|
+
person.errors.messages
|
994
996
|
# => {:name=>["can't be blank", "is too short (minimum is 3 characters)"]}
|
995
997
|
|
996
998
|
person = Person.new(name: "John Doe")
|
997
999
|
person.valid? # => true
|
998
|
-
person.errors # =>
|
1000
|
+
person.errors.messages # => {}
|
999
1001
|
```
|
1000
1002
|
|
1001
1003
|
### `errors[]`
|