Created
July 17, 2017 23:33
-
-
Save msimonborg/b620cce4d7ea40f89d108d35318b35a5 to your computer and use it in GitHub Desktop.
When a scope method name collides with a Kernel method, calling with #send on an ActiveRecord::Relation doesn't work
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
require "bundler/inline" | |
rescue LoadError => e | |
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler" | |
raise e | |
end | |
gemfile(true) do | |
source "https://rubygems.org" | |
# Activate the gem you are reporting the issue against. | |
gem "activerecord", "5.1.0" | |
gem "sqlite3" | |
end | |
require "active_record" | |
require "minitest/autorun" | |
require "logger" | |
# Ensure backward compatibility with Minitest 4 | |
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) | |
# This connection will do for database-independent bug reports. | |
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
ActiveRecord::Schema.define do | |
create_table :posts, force: true do |t| | |
end | |
create_table :comments, force: true do |t| | |
t.integer :post_id | |
end | |
end | |
class Post < ActiveRecord::Base | |
has_many :comments | |
# A scope whose name collides with Kernel, in this case Kernel#open | |
def self.open | |
"inside open" | |
end | |
end | |
class Comment < ActiveRecord::Base | |
belongs_to :post | |
def self.open | |
"inside open" | |
end | |
end | |
class BugTest < Minitest::Test | |
def test_association_stuff | |
post = Post.create! | |
post.comments << Comment.create! | |
assert_equal 1, post.comments.count | |
assert_equal 1, Comment.count | |
assert_equal post.id, Comment.first.post.id | |
end | |
# When calling scopes dynamically with #send based on params values, | |
# unexpected results are returned if the scope name collides with a Kernel method. | |
# This test will fail with an ArgumentError because send bypasses #method_missing | |
# on its way up the class heirarchy, and ActiveRecord relies on #method_missing to define | |
# scopes on ActiveRecord::Relation descendant classes. The message ends up hitting | |
# the Kernel implementation of #open. | |
def test_send_with_kernel_method | |
posts = Post.all | |
params = { status: "open" } | |
assert_equal "inside open", posts.send(params[:status]) | |
end | |
# After calling the scope directly, thereby defining the method on | |
# Comment::ActiveRecord_Relation with a call to #method_missing, using #send will work. | |
def test_send_with_kernel_method_after_calling_it_directly | |
comments = Comment.all | |
params = { status: "open" } | |
assert_equal "inside open", comments.open | |
assert_equal "inside open", comments.send(params[:status]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment