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
(或 ag
或 ack
)代码库寻找对 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
Doorman
和Bartender
都有一个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" 不是函数,而是传递给对象并由该对象处理的消息。
参考资料
- How to use concerns in Rails 4
- http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
- http://guides.rubyonrails.org/command_line.html#rails-console
我正在处理一个庞大的遗留代码库,所以我正在寻找关于这个特定问题的建议,而不是更好的高级实现的建议。
我正在使用的简化版本:
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
(或 ag
或 ack
)代码库寻找对 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
Doorman
和Bartender
都有一个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" 不是函数,而是传递给对象并由该对象处理的消息。
参考资料
- How to use concerns in Rails 4
- http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
- http://guides.rubyonrails.org/command_line.html#rails-console