2

データベースの一部のフィールドで暗号化を使用する必要があるアプリケーションがあります。これは現在、含まれるクラスのフィールドの暗号化と管理の詳細を処理する懸念を使用して実装されています。どのクラスにこの問題が含まれているかをシステムがプログラムで判断できることが重要ですが、さらに具体的には、どのフィールドが暗号化されているかをプログラムで判断する適切な方法が必要です。

今日、これは次のようなクラス変数を使用して実装され、機能しています。

module EncryptedFields

    extend ActiveSupport::Concern

    included do
        @@encrypted_attributes ||= {}
        @@encrypted_attributes[self.to_s] ||= []

        def self.encrypted attribute, options={}

            @@encrypted_attributes[self.to_s] << attribute

            ### Other stuff
        end
    end
end

次のように、クラスに含まれます。

class SomeEcryptedModel

   include EncryptedFields

   encrypted :field_name, options
   encrypted :other_field_name, options

   #etc
end

クラス変数@@encrypted_attributesは、含まれているクラス名をキーとして、暗号化された属性の配列を値として、キーと値のペアのハッシュを正しくキャプチャします。暗号化されたモデルがそれ自体とその属性を使用して「登録」するための登録システムを使用することを検討しましたが、これに関連するオーバーヘッドがはるかに多く、私のタイムラインでは、それほど安全でない場合は、より単純なものから始めたいと考えています.

これは現在のアプリケーションで実際にうまく機能していますが、懸念やクラス変数の経験があまりないため、これがどのように動作するかについて重大な誤算をしていないか心配しています. ここの落とし穴はどこですか?Ruby を使い始めてから (それほど前ではありませんが)、クラス変数は一般的に避けるようにプログラムされています。

最初はクラス変数が含まれるクラスのクラス変数になると思っていたので、私はこれに一度噛まれまし@@encrypted_attributesた。これは明らかにそうではありませんでした。それを含む新しいモデルごとにそれが上書きされるため、このクラス変数自体が明らかに問題であるという結論に達しました。少なくとも、これは私が目撃しているように見える行動です。暗号化されたモデルの完全なリストを取得できるようになったため、これは最終的により望ましい動作であることが判明しました。これには、ロードされたモデルの暗号化されたモデルと属性のリストしか返せないという明らかな制限があります。

だから、私の質問:

これはクラス変数の適切な使用例ですか、それとも同じ情報を取得する別の (より良い?) 方法はありますか? これが受け入れられるクラス変数の使用例である場合、コードが意図したとおりに機能することを保証するために追加する必要がある落とし穴や保護は何ですか?

多分私はあまりにも賢くしようとしているだけで、リストをハードコーディングする必要がありますか? 助けてくれてありがとう!

4

1 に答える 1

4

アプローチを懸念する代わりに、この方法を使用できます。

module EncryptedFields
  @encrypted_attributes ||= {}

  def self.included(klass)
    @encrypted_attributes[klass.name] ||= []
    klass.extend(ClassMethods)
  end

  def self.add(class_name, attribute)
    @encrypted_attributes[class_name] << attribute
  end

  module ClassMethods
    def encrypted(attribute, options={})
      EncryptedFields.add(name, attribute)
      # Other stuff
    end
  end
end

class Stuff
  include EncryptedFields

  encrypted :ololo
  encrypted :new_name
end

EncryptedFields.instance_variable_get(:@encrypted_attributes)
=> {"Stuff"=>[:ololo, :new_name]}

ここではクラス変数は必要ありません。モジュールのインスタンス変数で十分です。継承はなく、実際にモジュールのインスタンスを作成することはできないため、@encripted_attributes変数が定義される場所は常に 1 つだけであり、それがEncriptedFieldsモジュールになります。

クラス変数とクラス インスタンス変数の違いに関する良い記事: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/

于 2016-08-05T15:13:02.850 に答える