提交 9bfe89e6 编写于 作者: T Tom Rossi

Introducing the `where.missing` query method.

上级 c2d7bdc6
* Find orphans by looking for missing relations through chaining `where.missing`:
Before:
```ruby
Post.left_joins(:author).where(authors: { id: nil })
```
After:
```ruby
Post.where.missing(:author)
```
*Tom Rossi*
* Ensure `:reading` connections always raise if a write is attempted.
Now Rails will raise an `ActiveRecord::ReadOnlyError` if any connection on the reading handler attempts to make a write. If your reading role needs to write you should name the role something other than `:reading`.
......
......@@ -70,6 +70,35 @@ def not(opts, *rest)
@scope
end
# Returns a new relation with left outer joins and where clause to idenitfy
# missing relations.
#
# For example, posts that are missing a related author:
#
# Post.where.missing(:author)
# SELECT "posts".* FROM "posts"
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
# WHERE "authors"."id" IS NULL
#
# Additionally, multiple relations can be combined. This will retrun posts
# that are missing both an author and any comments:
#
# Post.where.missing(:author, :comments)
# SELECT "posts".* FROM "posts"
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
# LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
# WHERE "authors"."id" IS NULL AND "comments"."id" IS NULL
def missing(*args)
args.each do |arg|
reflection = @scope.klass._reflect_on_association(arg)
opts = { reflection.table_name => { reflection.association_primary_key => nil } }
@scope.left_outer_joins!(arg)
@scope.where!(opts)
end
@scope
end
private
def not_behaves_as_nor?(opts)
return false unless opts.is_a?(Hash)
......
......@@ -2,17 +2,30 @@
require "cases/helper"
require "models/post"
require "models/author"
require "models/comment"
require "models/categorization"
module ActiveRecord
class WhereChainTest < ActiveRecord::TestCase
fixtures :posts
fixtures :posts, :authors
def setup
super
@name = "title"
end
def test_missing_with_association
assert posts(:authorless).author.blank?
assert_equal [posts(:authorless)], Post.where.missing(:author).to_a
end
def test_missing_with_multiple_association
assert posts(:authorless).comments.empty?
assert_equal [posts(:authorless)], Post.where.missing(:author, :comments).to_a
end
def test_not_inverts_where_clause
relation = Post.where.not(title: "hello")
expected_where_clause = Post.where(title: "hello").where_clause.invert
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册