Question

I have a before_save filter called :strip_whitespaces on a Rails model like this

  before_save :strip_whitespaces

The strip_whitespaces filter is a private method which is defined in the following way:

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

How do I use ruby's send method to make this method DRY-er? This also helps once I have to add more fields to this filter.

I had something like this in mind but it does not work

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

Solution

I'd even be tempted split it into two private methods:

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

Note that you don't need to do self.send - the self is implied - and also you don't need to do send("#{attr}") because that interpolation achieves nothing, you can just do send(attr).

OTHER TIPS

This answer has a good description to the setter syntax on the send method of a ruby object - How to set "programmatically"\"iteratively" each class object attribute to a value?

The problem in this particular case was solved by using the following code

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

Here, the code gets the the current value of the attribute self.send("#{attr}") first, strips off white-spaces, and then sets it to attribute through "#{attr}=" setter. attribute_present?(attr) is a method on the ActiveRecord::Base class which returns false if the atribute is not present.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top