Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 932
p.matsinopoulos Avatar asked Jun 30 '11 18:06

p.matsinopoulos


3 Answers

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
like image 89
Keith Gaddis Avatar answered Oct 20 '22 04:10

Keith Gaddis


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.

like image 33
p.matsinopoulos Avatar answered Oct 20 '22 02:10

p.matsinopoulos


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
like image 29
bradlis7 Avatar answered Oct 20 '22 03:10

bradlis7