diff options
author | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2014-02-18 14:06:29 -0300 |
---|---|---|
committer | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2014-02-18 14:06:29 -0300 |
commit | 6c496a6d2a21fb8f6f5fb4a97acf1f2de828d1d5 (patch) | |
tree | 0baea8c974793ececf2080aed70d29832f41c280 /guides | |
parent | 67e57ea7c0032815aef4cd9c02792c9badf90abe (diff) | |
parent | fc641a1a5b2162530482697bc1fec2a6d4ca1d5c (diff) | |
download | rails-6c496a6d2a21fb8f6f5fb4a97acf1f2de828d1d5.tar.gz rails-6c496a6d2a21fb8f6f5fb4a97acf1f2de828d1d5.tar.bz2 rails-6c496a6d2a21fb8f6f5fb4a97acf1f2de828d1d5.zip |
Merge pull request #14095 from rails/rm-scopes
Document `default_scope` changes
Diffstat (limited to 'guides')
-rw-r--r-- | guides/source/4_1_release_notes.md | 6 | ||||
-rw-r--r-- | guides/source/active_record_querying.md | 24 | ||||
-rw-r--r-- | guides/source/upgrading_ruby_on_rails.md | 67 |
3 files changed, 85 insertions, 12 deletions
diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md index 8fcfc71351..a0b143d74c 100644 --- a/guides/source/4_1_release_notes.md +++ b/guides/source/4_1_release_notes.md @@ -453,6 +453,12 @@ for detailed changes. ### Notable changes +* Default scopes are no longer overriden by chained conditions. + + Before this change when you defined a `default_scope` in a model + it was overriden by chained conditions in the same field. Now it + is merged like any other scope. [More Details](upgrading_ruby_on_rails.html#changes-on-default-scopes). + * Added `ActiveRecord::Base.to_param` for convenient "pretty" URLs derived from a model's attribute or method. ([Pull Request](https://github.com/rails/rails/pull/12891)) diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index d164b08d93..4900f176a6 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -707,7 +707,7 @@ You can additionally unscope specific where clauses. For example: ```ruby Post.where(id: 10, trashed: false).unscope(where: :id) -# => SELECT "posts".* FROM "posts" WHERE trashed = 0 +# SELECT "posts".* FROM "posts" WHERE trashed = 0 ``` A relation which has used `unscope` will affect any relation it is @@ -715,7 +715,7 @@ merged in to: ```ruby Post.order('id asc').merge(Post.unscope(:order)) -# => SELECT "posts".* FROM "posts" +# SELECT "posts".* FROM "posts" ``` ### `only` @@ -1242,26 +1242,26 @@ class User < ActiveRecord::Base end User.active.inactive -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'inactive' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'inactive' ``` We can mix and match `scope` and `where` conditions and the final sql -will have all conditions joined with `AND` . +will have all conditions joined with `AND`. ```ruby User.active.where(state: 'finished') -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'finished' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' AND "users"."state" = 'finished' ``` If we do want the `last where clause` to win then `Relation#merge` can -be used . +be used. ```ruby User.active.merge(User.inactive) -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' ``` -One important caveat is that `default_scope` will be overridden by +One important caveat is that `default_scope` will be prepended in `scope` and `where` conditions. ```ruby @@ -1272,16 +1272,16 @@ class User < ActiveRecord::Base end User.all -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' User.active -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'active' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active' User.where(state: 'inactive') -# => SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive' ``` -As you can see above the `default_scope` is being overridden by both +As you can see above the `default_scope` is being merged in both `scope` and `where` conditions. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index f28f6dc576..76722c9ea9 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -262,6 +262,73 @@ authors = Author.where(name: 'Hank Moody').to_a authors.compact! ``` +### Changes on Default Scopes + +Default scopes are no longer overriden by chained conditions. + +In previous versions when you defined a `default_scope` in a model +it was overriden by chained conditions in the same field. Now it +is merged like any other scope. + +Before: + +```ruby +class User < ActiveRecord::Base + default_scope { where state: 'pending' } + scope :active, -> { where state: 'active' } + scope :inactive, -> { where state: 'inactive' } +end + +User.all +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' + +User.active +# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' + +User.where(state: 'inactive') +# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +``` + +After: + +```ruby +class User < ActiveRecord::Base + default_scope { where state: 'pending' } + scope :active, -> { where state: 'active' } + scope :inactive, -> { where state: 'inactive' } +end + +User.all +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' + +User.active +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active' + +User.where(state: 'inactive') +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive' +``` + +To get the previous behavior it is needed to explicitly remove the +`default_scope` condition using `unscoped`, `unscope`, `rewhere` or +`except`. + +```ruby +class User < ActiveRecord::Base + default_scope { where state: 'pending' } + scope :active, -> { unescope(where: :state).where(state: 'active') } + scope :inactive, -> { rewhere state: 'inactive' } +end + +User.all +# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' + +User.active +# SELECT "users".* FROM "users" WHERE "users"."state" = 'active' + +User.inactive +# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive' +``` + Upgrading from Rails 3.2 to Rails 4.0 ------------------------------------- |