p.matsinopoulos
p.matsinopoulos

Reputation: 7810

How can I make Rails ActiveRecord automatically truncate values set to attributes with maximum length?

Assuming that I have a class such as the following:

class Book < ActiveRecord::Base

  validates :title, :length => {:maximum => 10}

end

Is there a way (gem to install?) that I can have ActiveRecord automatically truncate values according to maximum length?

For instance, when I write:

b = Book.new
b.title = "123456789012345" # this is longer than maximum length of title 10
b.save

should save and return true?

If there is not such a way, how would you suggest that I proceed facing such a problem more generally?

Upvotes: 9

Views: 3966

Answers (4)

Duke
Duke

Reputation: 7442

I like the idea of using the before_validation callback. Here's my stab that automatically truncates all strings to within the database's limit

  before_validation :truncate_strings

  def truncate_strings
    self.class.columns.each do |column|
      next if column.type != :string

      if self[column.name].length > column.limit
        self[column.name] = self[column.name][0...column.limit]
      end
    end
  end

Upvotes: 2

bradlis7
bradlis7

Reputation: 3489

This may not have been an option in 2011, but now there's a before_validation callback that will work.

class Book < ApplicationRecord
  before_validation do
    if self.params && self.params.length > 1000
      self.params = self.title[0...10] 
    end
  end

  validate :title, length: { maximum: 10 }, allow_nil: true
end

Upvotes: 2

p.matsinopoulos
p.matsinopoulos

Reputation: 7810

I have come up with a new validator that does truncation. Here is how I did that:

I created the "validators" folder inside "app" folder and then created the file "length_truncate_validator.rb" with the following content:

class LengthTruncateValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    ml = options[:maximum]
    record.send("#{attribute}=", value.mb_chars.slice(0,ml)) if value.mb_chars.length > ml unless value.nil? or ml.nil?
  end

  class << self
    def maximum(record_class, attribute)
      ltv = record_class.validators_on(attribute).detect { |v| v.is_a?(LengthTruncateValidator) }
      ltv.options[:maximum] unless ltv.nil?
    end
  end

end

And inside my model class I have something like:

class Book < ActiveRecord::Base

  validates :title, :length_truncate => {:maximum => 10}

end

which is quite handy and works the way I require.

But still, if you think that this one can be improved or done in another way, you are welcome.

Upvotes: 2

Keith Gaddis
Keith Gaddis

Reputation: 4113

Well, if you want the value truncated if its too long, you don't really need a validation, because it will always pass. I'd handle that like this:

class Book < ActiveRecord::Base
  before_save :truncate_values
  def truncate_values
    self.title = self.title[0..9] if self.title.length > 10
  end
end

Upvotes: 6

Related Questions