Обертывание методов ActiveRecord с дополнительным функционалом - PullRequest
0 голосов
/ 01 сентября 2011

Я хочу улучшить сеттеры ActiveRecord в Rails, чтобы гарантировать сохранение только допустимых значений.Одним из таких мест, где это необходимо, являются номера телефонов.Пользователь может вводить телефонный номер в различных форматах, таких как

(123) 456-7890
+1 123-456-7890

, но я хочу сохранить цифры и отбросить остальные, когда он поступит в базу данных.Подход, который я использую сейчас, заключается в переопределении методов установки с использованием alias_method.Кроме того, я пытаюсь поместить это в модуль, чтобы любой класс модели, который содержит номер телефона, мог включать этот модуль и определять поля, которые должны быть очищены.Тип интерфейса, который я надеюсь использовать:

# Person has a "phone" attribute to store phone numbers
class Person < ActiveRecord::Base
  # first include this module
  include PhoneSanitizer

  # then call the class method and tell it which 
  # fields need need to be sanitized
  sanitize_phone_field :phone
end

Единственное, что я делаю в своих классах модели, - это включаю модуль PhoneSanitizer (который добавляет метод класса - sanitize_phone_field вPerson класс).Этот метод теперь отвечает за переопределение метода setter phone=.Это часть, которую я не получил работать.

module PhoneSanitizer

  module ClassMethods
    # wrap each of the passed-in fields with setters that
    # clean up the phone number value of non-digits.
    def sanitize_phone(*fields)
      fields.each do |field|
        new_method = "original_#{field}=".to_sym
        original_method = "#{field}=".to_sym
        alias_method new_method, original_method
        define_method(original_method) do |value|
          self.send(new_method, phone_to_number(value))
        end
      end
    end
  end

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

  def phone_to_number(number)
    number.gsub(/[^\d]/, '')
  end

end

Когда вызывается sanitize_phone, выдается ошибка, говорящая, что :phone= не определен для класса Person, и это имеет смысл,Как мне вместо этого использовать псевдоним метода для экземпляров Person?

1 Ответ

1 голос
/ 01 сентября 2011

Я думаю, что ваша ошибка не была undefined method alias_method, это было что-то другое, и вы неверно истолковали это (?)

Реальная проблема заключается в том, что методы получения и установки в ActiveRecord являются динамическими .Методы получения и установки (то есть phone и phone=) не создаются до тех пор, пока фактический объект AR не будет загружен из базы данных.В этот момент AR перечисляет поля БД и создает соответствующие методы поля.

Эти методы поля недоступны во время определения класса в вашем источнике, поэтому вы не можете alias_method метод, которыйне существует.Однако вы могли бы сделать что-то вроде этого (не проверено):

module PhoneSanitizer
  module ClassMethods
    def sanitize_phone(*fields)
      fields.each do |field|
        original_method = "#{field}=".to_sym
        define_method(original_method) do |value|
          self.write_attribute(field, phone_to_number(value))
        end
      end
    end
  end

  ...
end

Это должно выполнить почти то же самое, что вы изначально планировали:
http://apidock.com/rails/ActiveRecord/AttributeMethods/Write/write_attribute

...