Rails使用同名方法关联模型

时间:2015-10-12 16:05:01

标签: ruby-on-rails ruby overloading models

我正在使用庞大的遗留代码库,所以我正在寻找有关此特定问题的建议,而不是更好的高级实现的建议。

我正在使用的简化版本:

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

并且调用的balance方法是在该类的对象中定义的方法。在我所描述的情况中,我在实际的实时应用环境中观察到,在代码中的某个位置

LineItem.find(some_id).balance

被称为输出而不是由LineItem'balance'方法计算的结果,而是来自Order类的结果。

所以我希望得知有一些ruby怪癖可能会在某些条件下将对象称为同名的同名方法,而不是它自己的方法。但我认为这是不可能的,所以可能还有其他一些特定于此情况的内容。

1 个答案:

答案 0 :(得分:0)

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

要使Concern方法可用于给定对象,它必须是include在对象类的正文中。

如果您有权访问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" *的操作,你想要找的是之前的 .balance这个词,它是&#34;余额的接收者&#34;消息,如果该接收者是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是一种传递语言的消息&#34;和每个&#34;方法&#34;它不是一个函数,而是一个传递给对象并由该对象处理的消息。

<强>参考