2017-09-20 13 views
0

TL; DR; 別のモジュール(インクルード)内のインスタンスメソッドから見える1つのモジュール内の静的メソッド(extends)のいくつかの@@変数を作成する必要があります。モジュール内のRuby変数の可視性

これを実現するには、一度@@ var = valueを設定するだけでは、それを表示させるには不十分でしたか?

たぶんあなただけこんにちは、私はいくつかのフルテキストでMySQLのテーブルにインデックスに私のモデルにいくつかのデータをメソッドを追加したい4.


に疑問を私の大文字のコメント怒鳴るとジャンプを読むことができます検索フィールド。

はそれを達成するために、私は以下のモジュールを作成しました:

module ElasticFakeIndexing 

    module IndexingTarget 

    #instance method to be called on model to get data to save 
    def build_index_data 
     { 
     entity_id: self.id, 
     entity_type: self.class.name, 

     #UNABLE TO ACCESS IF SET ONLY WITH @@var=value. Why? 
     #AND ALMOST SURE THAT USING class_variable_set IS THE CAUSE OF CONFIGURATION OF ONE MODULE MESSING UP WITH ANOTHER'S 
     title: @@title_fields.collect{|prop| self.send(prop.to_sym)}.join(" || "), 
     description: @@description_fields.collect{|prop| self.send(prop.to_sym)}.join(" || "), 
     } 
    end 

    def self.included(base) 
     base.extend ClassMethods 
    end 

    module ClassMethods 

     #class method to declare/call at a given model 
     def elastic_fake(options = {}) 
     #Make sure we always get an array so we can use 'join' 
     title_arg = Array(options[:title]) 
     ElasticFakeIndexing::IndexingTarget.class_variable_set(:@@title_fields, title_arg) 
     description_arg = Array(options[:description]) 
     ElasticFakeIndexing::IndexingTarget.class_variable_set(:@@description_fields, description_arg) 
     extra_arg = Array(options[:extra]) 
     ElasticFakeIndexing::IndexingTarget.class_variable_set(:@@extra_args, extra_arg) 

     end 

    end 

    end 

end 

をそして私は私のモデルでは、このようにそれを使用します。

class SomeModel < ApplicationRecord 
    #includes the module 
    include ElasticFakeIndexing::IndexingTarget 

    ... 

    # 'static' method call to configure to all classes of this model 
    elastic_fake(title: "prop_a", description: ["prop_b", "prop_c", "prop_d"]) 
end 

そして、このように私のコードの何かのいくつかの時点で、

index_data = some_model_instance.build_index_data 
save_on_mysql_text_search_fields(index_data) 

しかし、私はいくつかの問題を抱えています。そして、いくつかの質問がある:私は/私のモジュールは、第2のモデルに含める使用するときに1つのモデルの構成は他に見えているよう

  1. は、見えます。そして私はエラーのような '無効なフィールド'を得ました。私は、例えば、それはこのために起こる推測: ElasticFakeIndexing :: IndexingTarget.class_variable_set(:@@ title_fields、title_arg)

  2. しかし、唯一@@設定title_fieldsがtitle_fieldsを作るのに十分ではなかったので、私はこの本になりましたbuild_index_dataインスタンスメソッドで表示されます。どうして?

  3. @title_fieldsだけを使用するだけでは、build_index_dataに表示されないのはなぜですか?
  4. フィールドのセットが各モデルの「静的」変数に設定され、インスタンスメソッドbuild_index_data内で表示されるように設計するにはどうすればよいですか?または、可能な解決策として、フィールドをインスタンス変数に入れて表示することができます。しかし、フィールドがモデルの1つのインスタンスから別のインスタンスに変更されないため、静的な変数でなければならないと思います...

任意の考えですか?スコープ/可視性の変数について何が欠けていますか?

あなたは

答えて

0

はRubyの変数に以下の記事を読むありがとう:

迅速なリマインダー:@@title_fields、クラス変数、作成時に初期化されなければなりません、インスタンス変数@title_fieldsにはそのような要件はありません。

+0

おかげのようなものを書くことができます提供しています。投稿する前に私が最後に読んだもの。私はもう一度読むつもりです...しかし、@@ varがクラスを含むすべてのクラスで同じようになった理由(なぜなら、「無効なフィールド」エラーが発生している)私が正しく理解していれば、@ varは "InnerModule"内で作成され、維持されていたため、すべての人に共有されました。それは何が起こったのですか?私はこの権利を持っていますか?クラスを含むそれぞれに@@ varを作る方法はありますか? –

+0

「作成時に初期化する必要があります」とは、私が含むクラスで何かする必要があることを意味しますか?これには、モジュール、クラスクラスのメソッド、およびこのクラスのメソッド@@ varを設定する必要があります。それは "作成時に初期化"として大丈夫ですか? –

0

クラス変数に頼る代わりに、クラス側のインスタンス変数を使用することをお勧めします。クラス変数は、モジュールを含む個々のモデル間で簡単に上書きされます。ただし、クラス側のインスタンス変数はsaveです。シンタックスシュガー(すなわちconcernclass_attribute)レールの一部を使用して

あなたは

module ElasticFakeIndexing 
    extend ActiveSupport::Concern 

    included do 
    class_attribute :title_fields, 
        :description_fields, 
        :extra_args 
    end 

    class_methods do 
    def elastic_fake(options = {}) 
     ... 
     self.title_fields = Array(options[:title]) 
     ... 
    end 
    end 

    def build_index_data 
    ... 
    title: self.class.title_fields ... 
    ... 
    end 
end 
+0

class_attributeを持つこの「もの」は、私の方法を思い出させます(間違っています)。あなたのコードと一致するようにコードを修正し、何が起こるかを確認しようとします。しかし、 '@' var varは私の含むオブジェクトの中で利用可能にすべきではありませんか?または@@ varはclass_attributeのように表示されますか? –

+0

'@@ var'(クラス変数)をインクルードクラスのインスタンスで直接利用することはできません。 '@ var'(インスタンス変数)にアクセスすることはできますが、クラスメソッドを使って値を代入することはできません。厳密に言えば、クラス変数内にクラス変数をラップすることができます。 'def text_fields @@ text_fields end'とインスタンス内で' self.class.text_fields'を使ってそれにアクセスしますが、これは他のクラスを含むクラスの値を上書きするクラスを含む問題を残します。 – ulferts

関連する問題