簡體   English   中英

Ruby on Rails Monkey修補Gem的模型

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM