2

У меня есть приложение rails 2, которое я пытаюсь изменить, чтобы до того, как атрибут был записан в мою базу данных MySql, он закодирован и прочитан, он декодируется (не все атрибуты, только предопределенные).Rails 2 hook для изменения данных перед его чтением/записью в MySQL DB

Я рассмотрел некоторые драгоценные камни, в частности, зашифрованные, но он не делает именно то, что я хочу (я также стараюсь избегать повторного обозначения любых существующих столбцов таблицы, что, по-видимому, является требованием для атр-зашифрованы).

Я добавил к моей модели фильтр before_save, чтобы выполнить модификацию атрибута, прежде чем он будет сохранен в БД, и я переопределил свой атрибут getter для декодирования. Хотя это работает, я хочу сделать декодирование ниже в стеке (т. Е. Сразу после чтения БД), чтобы все функционировало правильно, не требуя изменений в системе (это также упрощает логику при принятии решения о том, когда кодировать/декодировать).

Так что это означает, что я хочу сделать следующее:

1) В БД читать, сделать наоборот, так что, если я делаю Model.last значение для моего атрибута будет декодированного value (без явного вызова атрибута getter).

2) Переопределите методы find_by_ *, чтобы выполнить поиск по моему закодированному атрибуту сначала будет закодировать поисковый запрос, а затем выполнить запрос db с использованием этого значения.

Как бы я это сделал?

+0

как в сторону ...добавление шифрования для обеспечения безопасности в рельсах 2 приложения звучит как театр безопасности. Вам действительно нужно обновить приложение, так как рельсы 2 не поддерживаются. – DGM

ответ

0

Update: этот метод, к сожалению, не работает в Rails 2. Пользовательские сериализаторов вероятно добавлены в Rails 3.

Оригинальный ответ следующим образом:

Я думаю, вы можете попробовать использовать изготовленный под заказ serializer как описано в this blog post. Эта функция должна присутствовать даже в Rails 2 (в противном случае я думаю, что эти SO questions относительно этого не существовало).

Образец сериализатору который кодирует атрибут в Base64:

# app/models/model.rb 
class Model < ActiveRecord::Base 
    serialize :my_attr, MyEncodingSerializer 
end 

# lib/my_encoding_serializer.rb 
class MyEncodingSerializer 
    require "base64" 

    def self.load(value) 
    # called when loading the value from DB 
    value.present? ? Base64.decode64(value) : nil 
    end 

    def self.dump(value) 
    # called when storing the value into DB 
    value.present? ? Base64.encode64(value) : nil 
    end 
end 

Тест на консоли рельсах:

>> Model.create(my_attr: "my secret text") 
D, [2016-03-14T07:17:26.493598 #14757] DEBUG -- : (0.1ms) BEGIN 
D, [2016-03-14T07:17:26.494676 #14757] DEBUG -- : SQL (0.6ms) INSERT INTO `models` (`my_attr`) VALUES ('bXkgc2VjcmV0IHRleHQ=\n') 
D, [2016-03-14T07:17:26.499356 #14757] DEBUG -- : (4.4ms) COMMIT 
=> #<Model id: 4, my_attr: "my secret text"> 

Вы можете видеть, что значение my_attr получает автоматически кодируются перед сохранением в БД ,

Загрузка из БД, конечно, работает прозрачно тоже:

>> Model.last 
D, [2016-03-14T07:19:01.414567 #14757] DEBUG -- : Model Load (0.2ms) SELECT `models`.* FROM `models` ORDER BY `models`.`id` DESC LIMIT 1 
=> #<Model id: 4, my_attr: "my secret text"> 

Все искателя помощники должны работать также, например:

>> Model.find_by_my_attr("other text") 
D, [2016-03-14T07:20:06.125670 #14757] DEBUG -- : Model Load (0.3ms) SELECT `models`.* FROM `models` WHERE `models`.`my_attr` = 'b3RoZXIgdGV4dA==\n' LIMIT 1 
=> nil # nothing found here for wrong my_attr value 

>> Model.find_by_my_attr("my secret text") 
D, [2016-03-14T07:21:04.601898 #14757] DEBUG -- : Model Load (0.6ms) SELECT `models`.* FROM `models` WHERE `models`.`my_attr` = 'bXkgc2VjcmV0IHRleHQ=\n' LIMIT 1 
=> #<Model id: 4, my_attr: "my secret text"> # FOUND! 
+1

Я пробовал это, но не похоже, что пользовательские сериализаторы поддерживаются в Rails 2 (хотя я не видел конкретной документации по этому вопросу). Если я попытаюсь использовать этот подход на Rails 4, он будет работать, если я сделаю то же самое в своем проекте Rails 2, я получаю сообщение об ошибке «ActiveRecord :: SerializationTypeMismatch: атрибут должен был быть CustomEncoder, но был строкой» – Hawkeye001

+0

Понимаю. При изучении [исходного кода сериализации Rails 2] (http://apidock.com/rails/v2.3.8/ActiveRecord/AttributeMethods/unserialize_attribute) он работает по-разному. В Rails 2 класс (второй аргумент 'serialize') означает класс, для которого атрибут ** должен быть десериализован **. И атрибут всегда сериализуется (сохраняется в db) ** как YAML **. Итак, вы правы, и пользовательские сериализаторы не будут работать в Rails 2, извините. – BoraMa

0

Похоже рельсы 2 имеет «after_initialize» обратного вызова, который должен получить то, что вы хотите (при небольшом снижении производительности):

class Model < ActiveRecord::Base 
    after_initialize do |model| 
    # your decryption code here 
    end 
end 

http://guides.rubyonrails.org/v2.3.11/activerecord_validations_callbacks.html#after-initialize-and-after-find

+0

10dot, метод after_initialize, похоже, работает. Так что я сделал, это использовать before_save для кодирования данных до его записи в БД и after_initialize для его декодирования. Проблема, которую я сейчас имею в том, что, когда я извлекаю запись, а затем изменяю ее, в памяти значения кодируются. Я попытался добавить фильтр after_save, чтобы также выполнить декодирование, но вызов self [: attr] = «декодированное значение» вызывает инициирование активного откат записи ... Любая идея, что может быть причиной этого? – Hawkeye001

+0

Я думаю, это потому, что after_save все еще находится внутри блока транзакций для обновления db, поэтому изменение приведет к отказу проверки. Попробуйте вызвать .reload() на любом активном объекте записи, который вы обновляете после возвращения обновления ... Это должно заставить обратный вызов after_initialize снова срабатывать (я думаю). – 10dot