Kyle Decot
Kyle Decot

Reputation: 20815

serialize & before_save in Rails 4

I have a DocumentType model w/ a extensions attribute. In my form I'm allowing people to insert those extensions into the form.

I want to be able to parse that input before saving, stripping out any invalid options, convert it into an array and have Rails serialize it.

I have the following code but I just end up w/ the input that the user gave in the form instead of an array:

class DocumentType < ActiveRecord::Base
  serialize :extensions

  before_save :process_extensions

  def process_extensions
    self.extensions = [*self.extensions.gsub(/[^a-z ]+/i, '').split(' ')].uniq
  end
end

Upvotes: 2

Views: 3708

Answers (2)

boulder
boulder

Reputation: 3266

The key to understanding what's happening is knowing when serialization occurs. By inspecting serialization.rb in activerecord you'll see that the serialization magic happens by overriding type_cast_attribute_for_write, which is called on write_attribute. That is, on attribute assignment. So when you do:

document_type.extensions = something

something gets serialized and written to the extensions attribute. That is way before the save takes place. In fact, you don't even have to call save on document_type to have the attribute serialized.

The best workaround I know is to override extensions= on DocumentType. Something like:

def extensions=(value)
  value = [*value.gsub(/[^a-z ]+/i, '').split(' ')].uniq
  write_attribute :extensions, value
end

Upvotes: 11

Benjamin Bouchet
Benjamin Bouchet

Reputation: 13181

I believe this append because the value of extensions is serialized while the model is validated by Rails, and your process_extensions method is called later (before the model is saved) and does not act as expected

Try to use before_validate instead

before_validate :process_extensions

Upvotes: -1

Related Questions