問題
class Ticket < ApplicationRecord
enum status: {
open: 1,
closed: 2
}
end
上記の Ticket モデルでは、status カラムに Rails の enum を使っています。enum を定義すると、自動的に open
, closed
という名前のスコープも定義されます。
Ticket.open.to_sql #=> SELECT "tickets".* FROM "tickets" WHERE "tickets"."status" = 1
Ticket.closed.to_sql #=> SELECT "tickets".* FROM "tickets" WHERE "tickets"."status" = 2
この open
という名前が少し曲者です。モデルのクラスには Kernel から継承した open
という名前のプライベートメソッドが既に存在します。
pry(main)> $ Ticket.open
From: /Users/quanon/.rbenv/versions/2.3.4/lib/ruby/2.3.0/open-uri.rb @ line 29:
Owner: Kernel
Visibility: private
Number of lines: 11
def open(name, *rest, &block) # :doc:
if name.respond_to?(:open)
name.open(*rest, &block)
elsif name.respond_to?(:to_str) &&
%r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name &&
(uri = URI.parse(name)).respond_to?(:open)
uri.open(*rest, &block)
else
open_uri_original_open(name, *rest, &block)
end
end
そのせいで、クラスの読み込み時に
Creating scope :open. Overwriting existing method Ticket.open.
という警告が表示されてしまいます。
解決策
class Ticket < ApplicationRecord
class << self; undef :open; end
enum status: {
open: 1,
closed: 2
}
end
enum を定義する前に undef を使って open メソッドの定義を取り消します。
参考
- Rails 製のツールである Redmine の issue を参考にしました。