6

Votegem ( https://github.com/peteonrails/vote_fu ) がアプリケーションに提供する ActiveRecord モデル ( ) を拡張しようとしています。(つまり、 にはありませvote.rbapp/models)

私の最初のアプローチは、コードを含むというファイルを作成することでしたlib/extend_vote.rb:

Vote.class_eval do
  after_create :create_activity_stream_event
  has_one :activity_stream_event

  def create_activity_stream_event
    # something..
  end
end

これは最初の投票が作成されたときに機能しますが、後続の各投票を作成しようとするとエラーが発生しますTypeError (can't dup NilClass)

Voteこのエラーは、リクエストごとにクラスが自動的にリロードされるという事実によって引き起こされると思いますが、コードlib/extend_vote.rbはサーバーの起動時に一度だけロードされ、これによりhas_one :activity_stream_event関連付けが奇妙に動作します。(また、設定すると問題はなくなりconfig.cache_classes = trueますdevelopment.rb

この問題を解決するために、to_prepareブロックを my に追加して、リクエストごとに投票拡張機能をリロードさせようとしましたdevelopment.rb:

config.to_prepare do
  load 'extend_vote.rb'
end

これで(can't dup NilClass)問題は解決しますが、新しい投票を作成するたびに、create_activity_stream_eventコールバックが追加で呼び出されます。つまり、最初の投票では 1 回呼び出し、2 回目の投票では 2 回呼び出し、などです。つまり、to_prepareブロックがあまりにも積極的に拡張機能をリロードし、重複したコールバックを追加しているようです。

Voteこのモデルにメソッドとコールバックを追加する最良の方法は何ですか?

4

6 に答える 6

6

[更新:モジュールが同じクラスに複数回含まれるのを防ぐための適切なソリューションである必要があります]

ActiveSupport :: Concernを使用して、モジュールが複数回含まれるのを防ぐことができると思います。これにより、コールバックが数回呼び出されます。以下の例を参照してください。

module VotePatch
  extend ActiveSupport::Concern

  included do
    after_create :create_activity_stream_event
    has_one :activity_stream_event
  end

  module InstanceMethods
    def create_activity_stream_event
      #your code here
    end  
  end

end

Vote.send(:include, VotePatch)
于 2012-06-07T22:50:10.463 に答える
4

注意事項: これは非常に古い gem (最後のコミットは 3 年前のもの) であり、見た目からすると Rails 3.x ではそのままでは動作しません。Rails 3.x のエンジンでは、この種の作業がはるかに簡単になります。

私が理解しているように、最初のケースの問題は、投票モデルがリロードされることではなく(そうすべきではありません)、activity_stream_eventモデルがリロードされることです。activity_stream_event投票モデルが再ロードされないため、関連付けは再ロード前のクラスのバージョンにぶら下がったままになります。レールはリロードされる前にクラスを削除するため、これが問題を引き起こします。

これを使って、このハックを試してください:

#in config/initializers/abstract_vote.rb
AbstractVote = Vote
AbstractVote.abstract_class = true
Object.send :remove_const, :Vote

#in app/models/vote.rb

class Vote < AbstractVote
  after_create :create_activity_stream_event
  has_one :activity_stream_event

  def create_activity_stream_event
  end
end

これにより、gem の Vote クラスを継承する独自の Vote クラスを使用できるようになります。

しかし、繰り返しますが、より最新のものを見つけるか、独自のものを作成することをお勧めします (gem はわずか 250 行のルビです)。

于 2012-06-01T14:50:50.560 に答える
2

コメントで agmcleod が提案したことを試してみますが、lib に配置する代わりに、config/initializers/vote.rbに配置します。

 class Vote
   after_create :create_activity_stream_event
   has_one :activity_stream_event

   def create_activity_stream_event
   # something..
   end
 end

もちろん、gem をフォークして変更を加え、Gemfile でフォークしたバージョンにリンクすることもできます (これが私の好みです)。

于 2012-05-26T02:58:14.737 に答える
0

このようなことを試していただけますか:

class Vote
    after_create :create_activity_stream_event
    has_one :activity_stream_event

    def create_activity_stream_event
        # something..
    end
end

関数を追加して、関数「after_create」と「has_hone」を呼び出すよりも私は思います。

于 2012-06-01T14:01:01.753 に答える
0

あなたの問題は、クラスにモンキー パッチを適用していることが原因である可能性があります。Rails が定数をリロードしようとすると、ファイルは考慮されません。

以下に示すように、モジュール手法を使用してみてください。

というファイルを追加します。lib/vote_fu_extension.rb

module VoteFuExtension
  def self.included(base)
    base.has_one :activity_stream_event
    base.after_create :create_activity_stream_event
  end
  def create_activity_stream_event
    # something..
  end  
end
Vote.send(:include, VoteFuExtension)

というイニシャライザを追加しますconfig/initializers/vote_fu.rb

require "vote_fu_extension"

ノート

Voteモデルにクラス メソッドを追加する場合は、この回答を参照してください。

Shameless plug: 私のfork of the vote_fugem にはいくつかの新機能と拡張機能があります。

于 2012-06-07T23:59:52.223 に答える