Использование send в фильтре before_save

У меня есть фильтр before_save под названием :strip_whitespaces в модели Rails, подобной этой.

  before_save :strip_whitespaces

Фильтр strip_whitespaces — это закрытый метод, который определяется следующим образом:

private 
  def strip_whitespaces
    self.name = name.split.join(" ") if attribute_present?("name")
    self.description = description.split.join(" ") if attribute_present?("description")
    self.aliases = aliases.split.join(" ") if attribute_present?("aliases")
  end

Как использовать метод отправки ruby, чтобы сделать этот метод DRY-er? Это также помогает, когда мне нужно добавить больше полей в этот фильтр.

Я имел в виду что-то подобное, но это не работает

  %W[name description aliases].each do |attr|
    self.send(attr) = self.send(attr).split.join(" ") if attribute_present?(attr)
  end

person papdel    schedule 04.01.2013    source источник
comment
Спасибо! Вариант этого сработал - [:name, :description, :aliases].each do |attr| self.send( #{attr}=, self.send(#{attr}).split.join( )) конец   -  person papdel    schedule 04.01.2013


Ответы (2)


У меня даже возникло бы желание разделить его на два приватных метода:

def strip_whitespaces
  %w(name description aliases).each do |attribute|
    strip_whitespace_from attribute
  end
end

def strip_whitespace_from(attr)
  send("#{attr}=", send(attr).split.join(" ")) if attribute_present?(attr)
end

Обратите внимание, что вам не нужно делать self.send — подразумевается self — а также вам не нужно делать send("#{attr}"), потому что эта интерполяция ничего не дает, вы можете просто сделать send(attr).

person Andrew Haines    schedule 04.01.2013
comment
Это очень круто! Принять ваш ответ вместо моего, так как это круче. - person papdel; 04.01.2013

В этом ответе есть хорошее описание синтаксиса установщика для метода send объекта ruby ​​- Как программно\итеративно установить значение каждого атрибута объекта класса?

Проблема в этом конкретном случае была решена с помощью следующего кода

def strip_whitespaces
  [:name, :description, :aliases].each do |attr|
    self.send( "#{attr}=", self.send("#{attr}").split.join(" ") ) if attribute_present?(attr)
  end
end

Здесь код сначала получает текущее значение атрибута self.send("#{attr}"), удаляет пробелы, а затем устанавливает его в атрибут с помощью установщика "#{attr}=". attribute_present?(attr) — это метод класса ActiveRecord::Base, который возвращает false, если атрибут отсутствует.

person papdel    schedule 04.01.2013