Ruby Альтернатива использованию переменных класса в ActiveSupport::Concern
У меня есть приложение, которое требует использования шифрования для некоторых полей в базе данных. В настоящее время это реализуется с помощью задачи, которая обрабатывает тонкие детали шифрования и управления полями во включенных классах. Важно, чтобы система могла программно определять, какие классы включают эту проблему, но даже более конкретно программно должен быть хороший способ определить, какие поля зашифрованы.
Сегодня это реализовано, работает, используя переменные класса, как это:
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
будет переменной класса во включенном классе; это, видимо, было не так. Каждая новая модель, которая включала его, перезаписывала его, поэтому я пришел к выводу, что эта переменная класса, очевидно, относится к самой проблеме. По крайней мере, такое поведение я наблюдаю. В итоге это оказалось более желательным поведением, потому что теперь я могу получить полный список зашифрованных моделей. Это имеет очевидное ограничение: он может возвращать только список зашифрованных моделей и атрибутов для моделей, которые были загружены.
Итак, мой вопрос:
Это правильный вариант использования для переменных класса или есть альтернативный (лучший?) Способ сбора этой же информации? Если это приемлемый вариант использования переменной класса, какие некоторые подводные камни и / или средства защиты я должен добавить, чтобы код работал так, как я намеревался?
Может быть, я просто пытаюсь быть слишком умным, и я должен просто написать свой список? Спасибо за помощь!
1 ответ
Вы можете пойти по этому пути альтернативно, чтобы коснуться подхода:
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
переменная будет определена, и это будет вашим EncriptedFields
модуль.
Хорошая статья о разнице между переменными класса и переменными экземпляра класса: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/