Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@tomykaira
Created June 1, 2014 03:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomykaira/3a2658008d1c722161a8 to your computer and use it in GitHub Desktop.
Save tomykaira/3a2658008d1c722161a8 to your computer and use it in GitHub Desktop.
ActiveRecord 4.0.5 behaves unexpectedly when has-many relationship and `where_values` are used in the same query.
require 'active_record'
require 'sqlite3'
prepare = <<SQL
create table viewers (
id integer primary key autoincrement, name, created_at, updated_at
);
create table notes (
id integer primary key autoincrement, name, created_at, updated_at
);
create table note_viewers (
id integer primary key autoincrement, viewer_id, note_id, created_at, updated_at
);
SQL
unless File.exist?('test.sqlite3')
IO.popen('sqlite3 test.sqlite3', 'r+') do |io|
io.write prepare
io.close_write
puts io.gets
end
end
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'test.sqlite3')
class Viewer < ActiveRecord::Base
has_many :note_viewers
has_many :notes, through: :note_viewers
end
class Note < ActiveRecord::Base
has_many :note_viewers
has_many :viewers, through: :note_viewers
scope :name_1, lambda { where(name: 'note1') }
scope :name_2, lambda { where(name: 'note2') }
scope :interested, lambda {
l = name_1.where_values.reduce(:and) # THIS IS PROBLEM: where_values contains already applied viewer_id scoping
r = name_2.where_values.reduce(:and)
where(l.or(r))
}
end
class NoteViewer < ActiveRecord::Base
belongs_to :note
belongs_to :viewer
end
note1 = Note.create!(name: 'note1')
viewer1 = Viewer.create!(name: 'viewer1')
NoteViewer.create!(note: note1, viewer: viewer1)
puts viewer1.notes.interested.to_sql
# => SELECT "notes".* FROM "notes" INNER JOIN "note_viewers" ON "notes"."id" = "note_viewers"."note_id" WHERE "note_viewers"."viewer_id" = ? AND (("note_viewers"."viewer_id" = ? AND "notes"."name" = 'note1' OR "note_viewers"."viewer_id" = ? AND "notes"."name" = 'note2'))
p viewer1.notes.interested.count # => 0 ???
raw_connection = ActiveRecord::Base.connection.raw_connection
st = raw_connection.prepare(viewer1.notes.interested.to_sql)
st.execute(viewer1.id, viewer1.id, viewer1.id) do |result|
p result.count # => 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment