Проблема здесь в том, что имя сталкивается с Kernel#open
, которое используется для открытия потоков ввода-вывода.
irb(main):001:0> z = Zone.create
(0.2ms) BEGIN
Zone Create (0.8ms) INSERT INTO "zones" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2018-10-19 16:29:40.018339"], ["updated_at", "2018-10-19 16:29:40.018339"]]
(0.7ms) COMMIT
=> #<Zone id: 10, created_at: "2018-10-19 16:29:40", updated_at: "2018-10-19 16:29:40">
irb(main):002:0> z.orders.send(:open)
Creating scope :open. Overwriting existing method Order.open.
ArgumentError: wrong number of arguments (given 0, expected 1..3)
from (irb):2:in `initialize'
from (irb):2:in `open'
from (irb):2
irb(main):003:0> z.orders.method(:open)
=> #<Method: Order::ActiveRecord_Associations_CollectionProxy(Kernel)#open>
irb(main):004:0> z.orders.method(:open).call
ArgumentError: wrong number of arguments (given 0, expected 1..3)
from (irb):4:in `initialize'
from (irb):4:in `open'
from (irb):4:in `call'
from (irb):4
irb(main):005:0> z.orders
Order Load (0.8ms) SELECT "orders".* FROM "orders" INNER JOIN "customers" ON "orders"."customer_id" = "customers"."id" WHERE "customers"."zone_id" = $1 LIMIT $2 [["zone_id", 10], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy []>
irb(main):006:0> z.orders.open
Order Load (0.9ms) SELECT "orders".* FROM "orders" INNER JOIN "customers" ON "orders"."customer_id" = "customers"."id" WHERE "customers"."zone_id" = $1 AND "orders"."status" = $2 LIMIT $3 [["zone_id", 10], ["status", "open"], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation []>
Как вы можете видеть, сначала вызов переходит к Kernel#open
, а затем к методуопределяется областью действия после загрузки коллекции.Я предполагаю, что это из-за того, что ActiveRecord::Associations::CollectionProxy
делает своего рода ленивое проксирование к целевому классу ассоциации.Поскольку CollectionProxy
уже имеет метод open
(Kernel # open), он использует его вместо этого.
Простое решение здесь вместо динамического вызова заключается в использовании области действия, которая принимает аргумент:
class Order < ApplicationRecord
belongs_to :customer
scope :with_status, ->(status){ where(status: status.to_s) }
end
Или еще лучше использовать ActiveRecord::Enum
, который достаточно умен, чтобы правильно работать с прокси-сервером сбора.
class Order < ApplicationRecord
belongs_to :customer
# you need to change the DB column to an integer type
enum status: [:open, :closed]
end