diff options
-rw-r--r-- | activerecord/CHANGELOG.md | 61 | ||||
-rw-r--r-- | guides/source/4_1_release_notes.md | 6 | ||||
-rw-r--r-- | guides/source/upgrading_ruby_on_rails.md | 67 |
3 files changed, 134 insertions, 0 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 458b9d77c2..926270ddda 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,64 @@ +* 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. + + Before: + + 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"."status" = 'active' + + User.where(state: 'inactive') + # => SELECT "users".* FROM "users" WHERE "users"."status" = 'inactive' + + After: + + 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"."status" = 'pending' AND "users"."status" = 'active' + + User.where(state: 'inactive') + # => SELECT "users".* FROM "users" WHERE "users"."status" = 'pending' AND "users"."status" = 'inactive' + + To get the previous behavior it is needed to explicitly remove the + `default_scope` condition using `unscoped`, `unscope`, `rewhere` or + `except`. + + Example: + + 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"."status" = 'active' + + User.inactive + # => SELECT "users".* FROM "users" WHERE "users"."status" = 'inactive' + * Perform necessary deeper encoding when hstore is inside an array. Fixes #11135. 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/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 8aae3bbc1a..74cfa23649 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"."status" = 'active' + +User.where(state: 'inactive') +# => SELECT "users".* FROM "users" WHERE "users"."status" = '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"."status" = 'pending' AND "users"."status" = 'active' + +User.where(state: 'inactive') +# => SELECT "users".* FROM "users" WHERE "users"."status" = 'pending' AND "users"."status" = '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"."status" = 'active' + +User.inactive +# => SELECT "users".* FROM "users" WHERE "users"."status" = 'inactive' +``` + Upgrading from Rails 3.2 to Rails 4.0 ------------------------------------- |