Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore empty condition on #construct_relation_for_exists #34329

Merged
merged 1 commit into from Oct 27, 2018

Conversation

r7kamura
Copy link
Contributor

Summary

At fc0e335,

relation = relation.where(conditions)

was rewritten to:

relation.where!(condition)

This change accidentally changed the result of Topic.exists?({}) from true to false.

To fix this regression, I moved the blank check logic (opts.blank?) from #where to #where!.

I think #where! should be identical to #where, except that instead of returning a new relation, it adds the condition to the existing relation.

Details

Steps to reproduce

begin
  require "bundler/inline"
rescue LoadError
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise
end

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails", github: "rails/rails"
  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"

ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")

ActiveRecord::Schema.define do
  create_table :topics, force: true
end

ActiveRecord::Base.logger = Logger.new(STDOUT)

class Topic < ActiveRecord::Base
end

class ExistsTest < Minitest::Test
  def setup
    Topic.create!
  end

  def test_exists_with_empty_hash_argument
    assert_equal true, Topic.exists?({})
  end
end

Expected behavior

-- create_table(:topics, {:force=>true})
   -> 0.0024s
Run options: --seed 39899

# Running:

D, [2018-10-27T14:57:50.240167 #60154] DEBUG -- :    (0.0ms)  begin transaction
D, [2018-10-27T14:57:50.240357 #60154] DEBUG -- :   Topic Create (0.1ms)  INSERT INTO "topics" DEFAULT VALUES
D, [2018-10-27T14:57:50.240578 #60154] DEBUG -- :    (0.0ms)  commit transaction
D, [2018-10-27T14:57:50.241155 #60154] DEBUG -- :   Topic Exists (0.1ms)  SELECT 1 AS one FROM "topics" LIMIT ?  [["LIMIT", 1]]
.

Finished in 0.003765s, 265.6042 runs/s, 265.6042 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

Actual behavior

-- create_table(:topics, {:force=>true})
   -> 0.0024s
Run options: --seed 53123

# Running:

D, [2018-10-27T14:58:16.323575 #60237] DEBUG -- :    (0.0ms)  begin transaction
D, [2018-10-27T14:58:16.323774 #60237] DEBUG -- :   Topic Create (0.1ms)  INSERT INTO "topics" DEFAULT VALUES
D, [2018-10-27T14:58:16.323973 #60237] DEBUG -- :    (0.0ms)  commit transaction
D, [2018-10-27T14:58:16.324506 #60237] DEBUG -- :   Topic Exists (0.1ms)  SELECT 1 AS one FROM "topics" WHERE (1=0) LIMIT ?  [["LIMIT", 1]]
F

Failure:
ExistsTest#test_exists_with_empty_hash_argument [/Users/r7kamura/Desktop/test.rb:37]:
Expected: true
  Actual: false


rails test Users/r7kamura/Desktop/test.rb:36



Finished in 0.003548s, 281.8489 runs/s, 281.8489 assertions/s.
1 runs, 1 assertions, 1 failures, 0 errors, 0 skips

@rails-bot
Copy link

Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @rafaelfranca (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review.

Please see the contribution instructions for more information.

@kamipo
Copy link
Member

kamipo commented Oct 27, 2018

This changes the existing where behavior which return the same instance if empty args, it may affect to any apps.

How about just fixing construct_relation_for_exists?

diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 6f420fe6bb..55c387f7b7 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -363,7 +363,7 @@ def construct_relation_for_exists(conditions)
 
         case conditions
         when Array, Hash
-          relation.where!(conditions)
+          relation.where!(conditions) unless condition.empty?
         else
           relation.where!(primary_key => conditions) unless conditions == :none
         end

@kamipo
Copy link
Member

kamipo commented Oct 27, 2018

Note that where! is private API unlike where, people should not rely on the private API.

@r7kamura
Copy link
Contributor Author

I agree that we shouldn't change the existent #where behavior.

So here we can choose the one of following solutions I think:

  1. Change #construct_relation_for_exists (as you suggested)
  2. Change only #where! (and leave elsif opts.blank? in #where)

The advantage of 2nd option is we can still keep the same behavior on #where and #where! with blank argument. What do you think?

@kamipo
Copy link
Member

kamipo commented Oct 27, 2018

I'm not prefer to add extra / duplicated args checking #where! which is called in #where, and we'd not guarantee that #where! behave like #where since that is private API.

@r7kamura
Copy link
Contributor Author

Okay, it means it's a special feature of #where to handle blank conditions, and #where! doesn't have this feature.

In this case, just fixing #construct_relation_for_exists is the best solution 🥇

@r7kamura r7kamura changed the title Keep the same behavior on #where and #where! with blank argument Ignore empty condition on #construct_relation_for_exists Oct 27, 2018
Copy link
Member

@kamipo kamipo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
Can you squash your commits and include the context (Summary part in this PR) in the commit message?

@kamipo
Copy link
Member

kamipo commented Oct 27, 2018

ah I realized that 2nd commit includes the context. Please ignore about the commit message.

At rails@fc0e335,

```rb
relation = relation.where(conditions)
```

was rewritten to:

```rb
relation.where!(condition)
```

This change accidentally changed the result of `Topic.exists?({})` from true to false.

To fix this regression, first I moved the blank check logic (`opts.blank?`) from `#where` to `#where!`,
because I thought `#where!` should be identical to `#where`, except that instead of returning a new relation,
it adds the condition to the existing relation.

But on second thought after some discussion on rails#34329,
I started to think that just fixing `#construct_relation_for_exists` is more preferable
than changing `#where` and `#where!`.
@r7kamura r7kamura force-pushed the feature/where-exclamation-consistency branch from 79e42bd to 4694fcf Compare October 27, 2018 13:02
@r7kamura
Copy link
Contributor Author

Squashed the 2 commits into 4694fcf that has all the context of this PR in its commit message.

@kamipo kamipo merged commit 6c98dad into rails:master Oct 27, 2018
@kamipo
Copy link
Member

kamipo commented Oct 27, 2018

Thanks!

@r7kamura r7kamura deleted the feature/where-exclamation-consistency branch October 27, 2018 13:50
kamipo added a commit that referenced this pull request Oct 27, 2018
…sistency

Ignore empty condition on #construct_relation_for_exists
kamipo added a commit that referenced this pull request Oct 27, 2018
…sistency

Ignore empty condition on #construct_relation_for_exists
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants