{"action":"created","issue":{"url":"https://api.github.com/repos/rails/rails/issues/19882","labels_url":"https://api.github.com/repos/rails/rails/issues/19882/labels{/name}","comments_url":"https://api.github.com/repos/rails/rails/issues/19882/comments","events_url":"https://api.github.com/repos/rails/rails/issues/19882/events","html_url":"https://github.com/rails/rails/issues/19882","id":70518378,"number":19882,"title":"Regression - scope of a relation is applied to unrelated object","user":{"login":"phallguy","id":1594371,"avatar_url":"https://avatars.githubusercontent.com/u/1594371?v=3","gravatar_id":"","url":"https://api.github.com/users/phallguy","html_url":"https://github.com/phallguy","followers_url":"https://api.github.com/users/phallguy/followers","following_url":"https://api.github.com/users/phallguy/following{/other_user}","gists_url":"https://api.github.com/users/phallguy/gists{/gist_id}","starred_url":"https://api.github.com/users/phallguy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/phallguy/subscriptions","organizations_url":"https://api.github.com/users/phallguy/orgs","repos_url":"https://api.github.com/users/phallguy/repos","events_url":"https://api.github.com/users/phallguy/events{/privacy}","received_events_url":"https://api.github.com/users/phallguy/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rails/rails/labels/activerecord","name":"activerecord","color":"0b02e1"},{"url":"https://api.github.com/repos/rails/rails/labels/stale","name":"stale","color":"444444"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":11,"created_at":"2015-04-23T21:29:27Z","updated_at":"2015-08-25T06:06:11Z","closed_at":null,"body":"This appears to be an issue with current_scope caching at the class level. When a where condition uses a subquery, the current scope is merged into the subquery producing incorrect results.\r\n\r\nNote, this was previously submitted as #19804 but incorrectly closed. This is a breaking change from previously working code in v3.x that is now broken due to caching introduced in the 4.x line.\r\n\r\nTest cases\r\n\r\n```ruby\r\nunless File.exist?('Gemfile')\r\n  File.write('Gemfile', <<-GEMFILE)\r\n    source 'https://rubygems.org'\r\n    gem 'rails', github: 'rails/rails'\r\n    gem 'arel', github: 'rails/arel'\r\n    gem 'rack', github: 'rack/rack'\r\n    gem 'i18n', github: 'svenfuchs/i18n'\r\n    gem 'sqlite3'\r\n  GEMFILE\r\n\r\n  system 'bundle'\r\nend\r\n\r\nrequire 'bundler'\r\nBundler.setup(:default)\r\n\r\nrequire 'active_record'\r\nrequire 'minitest/autorun'\r\nrequire 'logger'\r\n\r\n# This connection will do for database-independent bug reports.\r\nActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')\r\nActiveRecord::Base.logger = Logger.new(STDOUT)\r\n\r\nActiveRecord::Schema.define do\r\n  create_table(:campaigns) do |t|\r\n    t.string :name\r\n  end\r\n\r\n  create_table(:participants) do |t|\r\n    t.integer :priority\r\n    t.references :campaign\r\n    t.references :user\r\n  end\r\n\r\n  create_table(:users) do |t|\r\n    t.string :name\r\n  end\r\nend\r\n\r\n\r\nclass Campaign < ActiveRecord::Base\r\n  has_many :participants, inverse_of: :resource\r\nend\r\n\r\nclass Participant < ActiveRecord::Base\r\n  belongs_to :user, inverse_of: :participants\r\n  belongs_to :campaign, inverse_of: :participants\r\n\r\n  # @!attribute priority\r\n  # @return [Integer] some arbitrary column to filter by.\r\n\r\n  scope :in_campaigns, ->( campaigns ) {\r\n    campaigns = campaigns.select( :id )\r\n    where( campaign_id: campaigns )\r\n  }\r\n\r\n  scope :with_priority, ->( priority ) {\r\n    where( priority: priority )\r\n  }\r\nend\r\n\r\nclass User < ActiveRecord::Base\r\n  has_many :participants, inverse_of: :user\r\n  has_many :campaigns, through: :participants\r\nend\r\n\r\n\r\nclass BugTest < Minitest::Test\r\n\r\n  def setup\r\n    @john  = User.create! name: \"John\"\r\n    @jane  = User.create! name: \"Jane\"\r\n\r\n    book  = Campaign.create! name: \"Book\"\r\n    shoe  = Campaign.create! name: \"Shoe\"\r\n\r\n\r\n    @john.participants.create campaign: book, priority: 1\r\n\r\n    @jane.participants.create campaign: shoe, priority: 1\r\n    @jane.participants.create campaign: book, priority: 5\r\n  end\r\n\r\n  def test_includes_intersection_when_filter_preceeds_join\r\n    participants = Participant.with_priority 1\r\n    participants = participants.in_campaigns( @jane.campaigns )\r\n\r\n    assert participants.size == 2\r\n  end\r\n\r\n  def test_includes_intersection_when_filter_succeeds_join\r\n    participants = Participant.in_campaigns( @jane.campaigns )\r\n    participants = participants.with_priority 1\r\n\r\n    assert participants.size == 2\r\n  end\r\n\r\nend\r\n```\r\n\r\nBoth tests should produce the same result. The order however becomes significant because the precondition `with_priority 1` is applied to `jane.campaigns`  in which there is only one participant in that campaign.\r\n\r\nYou can observe the incorrect behavior by examining the SQL itself. In both cases, the SQL generated should be\r\n\r\n```sql\r\nSELECT COUNT(*)\r\nFROM \"participants\"\r\nWHERE \"participants\".\"campaign_id\" IN\r\n    (SELECT \"campaigns\".\"id\"\r\n     FROM \"campaigns\"\r\n     INNER JOIN \"participants\" ON \"campaigns\".\"id\" = \"participants\".\"campaign_id\"\r\n     WHERE \"participants\".\"user_id\" = ?)\r\n  AND \"participants\".\"priority\" = ? \r\n\r\n[[\"user_id\", 4], [\"priority\", 1]]\r\n```\r\n\r\nNotice that priority is only applied once. In the failing test however, priority is applied twice:\r\n\r\n```sql\r\nSELECT COUNT(*)\r\nFROM \"participants\"\r\nWHERE \"participants\".\"priority\" = ?\r\n  AND \"participants\".\"campaign_id\" IN\r\n    (SELECT \"campaigns\".\"id\"\r\n     FROM \"campaigns\"\r\n     INNER JOIN \"participants\" ON \"campaigns\".\"id\" = \"participants\".\"campaign_id\"\r\n     WHERE \"participants\".\"priority\" = ?\r\n       AND \"participants\".\"user_id\" = ?) \r\n\r\n[[\"priority\", 1], [\"priority\", 1], [\"user_id\", 2]]\r\n```\r\n\r\nI've done some initial debugging and it seems to be related to the #scoping call using #current_scope when merging the in_campaigns scope, but #current_scope is overwritten to include the priority constraint wen the in_campaigns scope is resolved, and that applies an additional unwanted constraint.\r\n"},"comment":{"url":"https://api.github.com/repos/rails/rails/issues/comments/134491186","html_url":"https://github.com/rails/rails/issues/19882#issuecomment-134491186","issue_url":"https://api.github.com/repos/rails/rails/issues/19882","id":134491186,"user":{"login":"PikachuEXE","id":1018543,"avatar_url":"https://avatars.githubusercontent.com/u/1018543?v=3","gravatar_id":"","url":"https://api.github.com/users/PikachuEXE","html_url":"https://github.com/PikachuEXE","followers_url":"https://api.github.com/users/PikachuEXE/followers","following_url":"https://api.github.com/users/PikachuEXE/following{/other_user}","gists_url":"https://api.github.com/users/PikachuEXE/gists{/gist_id}","starred_url":"https://api.github.com/users/PikachuEXE/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PikachuEXE/subscriptions","organizations_url":"https://api.github.com/users/PikachuEXE/orgs","repos_url":"https://api.github.com/users/PikachuEXE/repos","events_url":"https://api.github.com/users/PikachuEXE/events{/privacy}","received_events_url":"https://api.github.com/users/PikachuEXE/received_events","type":"User","site_admin":false},"created_at":"2015-08-25T06:06:11Z","updated_at":"2015-08-25T06:06:11Z","body":"@phallguy Can you still reproduce this issue on 4.1/4.2/master?"}}