Rails 个具有同名方法的关联模型

Rails associated models with a method of the same name

我正在处理一个庞大的遗留代码库,所以我正在寻找关于这个特定问题的建议,而不是更好的高级实现的建议。

我正在使用的简化版本:

class Order < ActiveRecord::Base
   has_many :line_items
   #other stuff

   def balance
       #some definition
   end
end

class LineItem < ActiveRecord::Base
   belongs_to :order
   #other stuff
end

module Concerns
  module LineItems
    module Aggregates
      extend ActiveSupport::Concern
      #stuff

      def balance
          #some other definition
      end

    end
   end
end

Order 有一个名为 'balance,' 的方法,LineItem 的一个模块也有一个名为 'balance.' 的方法似乎大多数时候(在代码库的大多数地方),当 specific_line_item.balance 被调用时,它使用了 LineItem 模块下的方法定义,但有几个地方它改为调用 Order 中的方法。

在 Ruby/Rails 中有什么方法可以在方法调用时指定我想使用这两个中的哪一个?或者这里可能还有其他事情正在发生,因为 Ruby 没有方法重载,所以我在这里描述的问题是不可能的?

调用任一方法的所有相关案例都来自 line_item(即 specific_line_item.balance),所以我认为它总是会选择更接近家庭的方法,而不是使关联跳转并在没有被告知的情况下调用 Order 的 'balance' 方法。

编辑: 感谢您的回复!看来我的问题还不够清楚。我明白

之间的区别
Order.first.balance

LineItem.first.balance

并且被调用的平衡方法是在 class 中为该对象定义的方法。在我描述的情况下,我观​​察到,在实际的实时应用程序环境中,代码中的某个位置

LineItem.find(some_id).balance

被称为它输出的结果不是由 LineItem 'balance' 方法计算的结果,而是来自订单 class.

的结果

所以我希望了解到有一些 ruby 怪癖,可能有一个对象在某些条件下调用同名的关联方法,而不是它自己的方法。但我认为这是不可能的,所以在这种情况下可能还有其他事情在发生。

首先,ActiveRecord::Concern 可以改变很多行为,你遗漏了很多代码,最重要的是,我不知道它被注入到哪里,但我可以做出有根据的猜测。

要使 Concern 的方法在给定对象中可用,它必须 include 在对象的 class 主体中。

如果您有权访问 Order 对象的实例,则可以随时调用 balance 方法:

order = Orders.last         # grab the last order in your database
order.balance               # this will call Order#balance

如果你有 Order 那么你还可以获得 LineItem:

order.line_items.first.balance    # should call the Concerns:: LineItems::Aggregates#balance

您可以打开一个 Rails 控制台(使用 rails console)和 运行 上面的代码,看看它是否按您预期的那样工作。您将需要一个工作数据库来获得有意义的订单和余额,并且您可能需要四处寻找完整的订单,但是 Ruby 是探索的全部,而 REPL 是您要去的地方。

我还会 grep(或 agack)代码库寻找对 balance 的调用,可能会做类似 grep -r "(^|\s)\w+\.balance" * 的事情,什么你要找的是 before .balance 这个词,也就是 "balance" 消息的接收者,如果那个接收者是一个 Order 对象那么它会调用 Order#balance,如果它是 LineItem 对象,那么它会调用 Concerns:: LineItems::Aggregates#balance

我觉得你不熟悉 Ruby 的范例,如果是这样的话,那么一个例子可能会有所帮助。

让我们定义两个简单的 Ruby 对象:

class Doorman
  def greet
    puts "Good day to you sir!"
  end
end

class Bartender
  def greet
    puts "What are you drinking?"
  end
end

DoormanBartender都有一个greet方法,调用哪个方法取决于我们调用greet的对象。

# Here we instantiate one of each
a_doorman = Doorman.new
a_bartender = Bartender.new

a_doorman.greet      # outputs "Good day to you sir!"
a_bartender.greet    # outputs "What are you drinking?"

我们仍在使用一种名为 greet 的方法,但接收者决定调用哪个方法。

Ruby 是一个 "message passing language",每个 "method" 不是函数,而是传递给对象并由该对象处理的消息。


参考资料