Reputation: 7810
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
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
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
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
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