5

これはばかげているかもしれませんが、プロジェクトに必要なすべてのモデルを表す gem を含めています。to_custom_stringこれらのモデルの 1 つにメソッドを追加したいと思いPersonます。

私は(この例 に従って)これをやろうとしていました:config/initializers/extensions/person.rb

次のようなものが含まれていました:

class Person < ActiveRecord::Base
  def to_custom_string
    address.street.to_s
  end
end

Persongemのクラスにはhas_one :address関連付けがあります。

私が経験していた問題は、このパッチがPersonパッチを適用するのではなく、gem のクラスをオーバーライドしているように見えることでした。クレイジーなのは、このオーバーライド動作が rake を介してのみ発生したことです ( Persongem のクラスで宣言されたすべての関連付けが失われます)。

私のレーキタスクは次のようなものでした:

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宝石からapp/modelsディレクトリにコピーし、to_custom_stringそこにメソッドを配置することですが、これは間違っていることがわかっています。

Persona) irb は私のアソシエーションを保持したが、rake は保持しなかった理由、および b) どうすれば rake に協力してもらうことができるのか、誰か説明してもらえますか?

ありがとうございました!

4

2 に答える 2

8

まず、クラスを再度開く代わりに、モジュールを作成してそれを 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]

rakeではなくirbで機能する理由は、クラスの検索方法が異なるためだと思います。Irb(レールコンソールを実行して実行すると思われます)はすべてのクラスを一度にロードするため、エンジンからクラスをロードし、エンジンからのクラスが既に定義されているイニシャライザを実行します。私は(確かではありませんが)開発モードのRakeは定数の遅延読み込みを使用していると思います。そのため、最初にすべてのクラスをロードするのではなく、未定義の定数が見つかった場合にのみロードします。次に、その定数を定義している可能性のあるファイルを探し始めます。一部の Person をイニシャライザに配置したため、エンジンのモデルをまったく検索しません。Person がすでに定義されているのを確認した時点で発生します。そのため、クラスを再度開くのではなくモジュールを含めると役立つ場合があります->

于 2012-08-17T01:48:21.670 に答える
4

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 は、すべてのモデルを含むエンジンのクラスです。

于 2012-08-16T20:42:32.210 に答える