rails 4.0.13 → 4.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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[]`
|