[英]Ruby on Rails Monkey Patching a Gem's Model
這可能很愚蠢,但我要包含一個代表我項目所需模型的寶石。 我想在其中一個模型Person
添加一個方法to_custom_string
。
我試圖這樣做(按照這個例子): config/initializers/extensions/person.rb
其中包含的內容如下:
class Person < ActiveRecord::Base
def to_custom_string
address.street.to_s
end
end
gem中的Person
類具有has_one :address
關聯。
我遇到的問題是這個補丁似乎覆蓋了gem中的Person
類,而不是修補它。 令人抓狂的是,這種覆蓋行為只能通過rake來體驗(來自gem的Person
類中聲明的所有關聯都會丟失)。
我的佣金任務是這樣的:
namespace :convert
task :all_persons => :environment do
Person.where(:param => value).includes(:address).find_in_batches(:batch_size => 2000) do |persons|
persons.each do |person|
puts person.to_custom_string
end
end
end
end
調用bundle exec rake convert:all_persons
給了我:
Association named 'address' was not found; perhaps you misspelled it?
但是將rake任務中的代碼復制並粘貼到rails控制台中工作正常。
我目前的解決方案是將Person
的代碼從gem復制到我的app/models
目錄中,並在那里使用我的to_custom_string
方法,我知道這是錯誤的。
有人可以解釋為什么a)irb保留了我的Person
協會,但是rake沒有,和b)我怎么可以得到佣金合作?
謝謝!
首先,我將創建一個Module並將其包含在Person中,而不是重新打開該類。 所以它看起來像那樣
module CustomString
def to_custom_string
address.street.to_s
end
end
Person.send(:include, CustomString)
此外,似乎Person模型在運行初始化程序時尚不可用。 如果仍然不起作用,您可能希望將它放在application.rb中。
config.railties_order = [ModelEngine::Engine, :main_app, :all]
我猜它在irb而不是rake中工作的原因是因為它們以不同的方式查找類。 Irb(我相信你通過運行rails控制台運行)一次加載所有類,因此它從引擎加載類,然后它運行初始化程序,你已經定義了引擎中的類。 我猜(雖然我不確定)Rake在開發模式下使用延遲加載常量。 所以它不會在最開始時加載所有類,只有在找到未定義的常量時才會加載。 然后它開始尋找可以定義該常量的文件。 由於你在初始化程序中放置了一些Person,因此它不會查找引擎的模型,因為它看到Person已經具有Person定義。 這就是為什么包含模塊而不是重新打開類可能會有所幫助 - >它強制它將從引擎中查找Person常量。
我認為只要你重新打開這個類就可以工作,而不必再次繼承ActiveRecord :: Base。 所以,像這樣:
class Person
def custom_string
address.to_street.to_s
end
end
編輯:
在重新打開課程之前,您可能還需要添加這樣的一行:
require_dependency ModelEngine::Engine.root.join('app', 'models', 'person').to_s
其中ModelEngine :: Engine只是包含所有模型的引擎的類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.