【问题标题】:How can I make Rails ActiveRecord automatically truncate values set to attributes with maximum length?如何使 Rails ActiveRecord 自动截断设置为具有最大长度的属性的值?
【发布时间】:2011-06-30 18:44:03
【问题描述】:

假设我有一个如下的类:

class Book < ActiveRecord::Base

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

end

有没有办法(gem 安装?)我可以让 ActiveRecord 根据最大​​长度自动截断值?

例如,当我写作时:

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

应该保存并返回true吗?

如果没有这样的方法,你会建议我如何更普遍地面对这样的问题?

【问题讨论】:

    标签: ruby-on-rails activerecord attributes max


    【解决方案1】:

    好吧,如果您希望该值太长而被截断,那么您实际上不需要验证,因为它总是会通过。我会这样处理:

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

    【讨论】:

    • 我不完全同意你的看法。我的业务规则说:“标题小于或等于 10 是有效的,即使这是截断的结果”。 validates :title, :length =&gt; {:maximum =&gt; 10, :truncate =&gt; true} 对我来说是完美的解决方案。
    【解决方案2】:

    我想出了一个新的截断验证器。我是这样做的:

    我在“app”文件夹中创建了“validators”文件夹,然后创建了文件“length_truncate_validator.rb”,内容如下:

    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
    

    在我的模型类中,我有类似的东西:

    class Book < ActiveRecord::Base
    
      validates :title, :length_truncate => {:maximum => 10}
    
    end
    

    这很方便,可以按我的要求工作。

    但是,如果您认为可以改进或以其他方式完成,欢迎您。

    【讨论】:

    • 这行得通,但我认为它更像是一种 hack,因为它使用了验证器,但实际上并没有执行任何验证。
    • 我同意马特的观点。虽然可以使用验证钩子来执行此操作,但这是一种 hack,因为它不是 Rails 样式的验证。验证器不应该修改对象,只是根据需要添加到错误集合中。如果您想强制截断,那么(冗余地)验证字段长度,只需使用 karmajunkie 的解决方案,但使用 before_validation 回调触发它,然后使用标准长度验证器。
    • 验证检查状态。使用回调来改变状态。
    【解决方案3】:

    这在 2011 年可能不是一个选项,但现在有一个可以工作的 before_validation 回调。

    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
    

    【讨论】:

      【解决方案4】:

      我喜欢使用 before_validation 回调的想法。这是我的 stab,它会自动将所有字符串截断到数据库的限制范围内

        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
      

      【讨论】:

      • 这是从列定义中提取的吗?例如 varchar(132) 会在 char 132 处截断
      猜你喜欢
      • 2016-01-13
      • 2011-02-14
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-14
      • 2012-06-14
      相关资源
      最近更新 更多