Изменить значение перед использованием в SQL, где предложение? - PullRequest
0 голосов
/ 21 октября 2018

Есть ли способ, которым я могу изменить значение в моей модели, прежде чем оно перейдет к MySQL в предложении WHERE?

В частности, я работаю с телефонными номерами и для обеспечения конфиденциальности пользователей,Я храню только хешированные номера телефонов SHA256 в БД. Но , я хочу иметь возможность работать с моделью так, как будто она не хэширована.

Например:

def phone_number=(number)
    write_attribute(:phone_number, OpenSSL::HMAC.hexdigest('SHA256', 'salt', number))
end

Это позволяет мне сохранить необработанный номер телефона.и имейте это автоматическое хеширование.Но есть ли способ, которым я могу сделать

PhoneNumbers.where(phone_number: '555-1234')

и получить хешированный '555-1234' до его перевода в SQL?

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Пользовательский Сериализатор отлично решил мой сценарий использования!

# lib/serializers/phone_hash_serializer.rb
class PhoneHashSerializer
  def self.load(value)
    value.to_s
  end

  def self.dump(value)
    value = value.to_s
    if value.start_with? 'hashed!'
      value
    else
      # Rails serializer's do not handle one-way hashing well, as the value ends up getting
      # getting dumped/hashed twice (once on the type-cast, then again before storing to DB).
      # So, we "tag" the value as "hashed!" to ensure we don't double hash since search's
      # only get hashed once, and would therefore never match the DB value
      'hashed!' + hash_string(value)
    end
  end

  private

  def self.hash_string(value)
    OpenSSL::HMAC.hexdigest('SHA256', 'hash_salt', value)
  end
end


# models/phone_number.rb
require 'serializers/phone_hash_serializer'
...
serialize :phone_number, PhoneHashSerializer
...

Я использовал http://ruby -journal.com / how-to-write-custom-serializer-for-activerecord-number-serialize / как моя муза.Спасибо тем, кто помог!

0 голосов
/ 21 октября 2018

Отметьте это https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html,, особенно заголовок Создание пользовательских типов.

Вы определяете пользовательский тип и задаете его в качестве типа вашего атрибута.Вы определяете метод «сериализации», который преобразует ваше значение в операторы SQL.

Из документов:

class Money < Struct.new(:amount, :currency)
end

class MoneyType < Type::Value
  def initialize(currency_converter:)
    @currency_converter = currency_converter
  end

  # value will be the result of +deserialize+ or
  # +cast+. Assumed to be an instance of +Money+ in
  # this case.
  def serialize(value)
    value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
    value_in_bitcoins.amount
  end
end

# config/initializers/types.rb
ActiveRecord::Type.register(:money, MoneyType)

# app/models/product.rb
class Product < ActiveRecord::Base
  currency_converter = ConversionRatesFromTheInternet.new
  attribute :price_in_bitcoins, :money, currency_converter: currency_converter
end

Product.where(price_in_bitcoins: Money.new(5, "USD"))
# => SELECT * FROM products WHERE price_in_bitcoins = 0.02230

Product.where(price_in_bitcoins: Money.new(5, "GBP"))
# => SELECT * FROM products WHERE price_in_bitcoins = 0.03412

Как вы можете видеть, метод where получает объект Money, ноОператор SQL имеет десятичное значение.

...