如何获取ActiveRecordvalidation中配置的最大长度?

鉴于一个模型:

class Person validates_lenght_of :name, :maximum => 50 end 

我有一些显示倒计时的视图代码并强制执行此最大值。 但是我将数字50硬编码到该视图代码中。 有没有办法从模型中提取这个数字?

就像是:

 Person.maximum_length_of_name 

我试过这个:

 Person.validators_on(:name) => [#true}, @klass=Trigger(id: integer, name: string, created_at: datetime, updated_at: datetime, user_id: integer, slug: string, last_update_by: integer)>, #, ##, :maximum=>50}>] 

信息在那里,但我不知道如何提取它:

使用validators_on方法

 irb(main):028:0> p Person.validators_on(:name)[0].options[:maximum] 50 => 50 

正如@Max Williams所说,它仅适用于Rails 3

@nash答案的问题是validation器不拥有某个订单。 我想出了如何用更多的代码来做同样的事情,但是在某种更安全的模式下(因为你可以在以后添加更多的validation器并打破你获得它的顺序):

 (Person.validators_on(:name).select { |v| v.class == ActiveModel::Validations::LengthValidator }).first.options[:maximum] 

我认为它也适用于Rails 3。

[编辑2017-01-17] Carefull我的答案是旧的(2012年),适用于Rails 3.它可能无法工作/适用于较新的Rails版本。


只是为了带来更多DRY精神,你可以创建一个generics类方法来获得任何属性的最大“length_validator”值,如下所示:

在lib目录中创建一个模块并使其扩展ActiveSupport :: Concern :

 module ActiveRecord::CustomMethods extend ActiveSupport::Concern end # include the extension ActiveRecord::Base.send(:include, ActiveRecord::CustomMethods) 

在其中添加“module ClassMethods”并创建“get_maximum”方法:

 module ActiveRecord::CustomMethods extend ActiveSupport::Concern module ClassMethods def get_maximum(attribute) validators_on(attribute).select{|v| v.class == ActiveModel::Validations::LengthValidator}.first.options[:maximum] end end end 

编辑1:配置

您还必须在其中一个初始值设定项中添加require。

例如,这是我的配置:

  1. 我把我的文件放在lib / modules / active_record / extensions中。
  2. 我已经在我的autoload_paths中添加了这个: config.autoload_paths += %W(#{config.root}/lib/modules) 注意:这不是必需的,但如果你想把一些自定义类和您在应用之间共享的模块。
  3. 在我的一个初始化器(config / initializers / custom.rb)中,我添加了这一行: require "active_record/extensions"

这应该做到! 重新启动服务器,然后……

结束编辑1

然后你应该可以做这样的事情:

 <%= form_for @comment do |f| %> <%= f.text_area(:body, :maxlength => f.object.class.get_maximum(:body)) #Or just use Comment.get_maximum(:body) %> <% end %> 

我希望它会帮助别人! :)当然,你可以按照你想要的方式自定义方法,添加选项并做一些奇特的东西。 😉

更简洁:

 Person.validators_on(:name).detect { |v| v.is_a?(ActiveModel::Validations::LengthValidator) }.options[:maximum] 

使用detect{}而不是select{}.first is_a?is_a? 而不是class ==
这也适用于Rails 4.1。

比Kulgar的答案更有活力的是使用这样的东西:

 Person.validators_on(attribute) .select { |v| v.class == ActiveRecord::Validations::LengthValidator } .select { |v| v.options[:maximum].present? }.first.options[:maximum] 

这样, 您可以按照自己的方式在模型中订购validation器

将它用作Rails助手

然后,您可以使用此代码编写帮助程序:

 # Returns the maximum length for a given attribute of a model def get_maxlength(model, attribute) model.validators_on(attribute) .select { |v| v.class == ActiveRecord::Validations::LengthValidator } .select { |v| v.options[:maximum].present? }.first.options[:maximum] end 

并使用这样的帮助:

 = f.text_field :name, maxlength: get_maxlength(f.object.class, :name) # Or use get_maxlength(Person, :name) 

如果你在轨道2中,这并不容易。 我记得以前尝试过这个并没有走远。 你可以得到validation对象但是它们没有列出它们对哪个字段来说对我来说似乎很奇怪。 人们为此做了插件(即检查或反思AR对象的validation),例如https://github.com/redinger/validation_reflection

Kulgar的答案很好,可能也很理想。 对于不需要修改任何配置的Rails 4,这是一种更简单的方法,缺点是你必须为每个想要使用它的模型添加一个include行。

车型/忧虑/ introspection.rb:

 module Introspection def self.included(base) base.extend(ClassMethods) end module ClassMethods def max_length(property) Resource.validators_on(property.to_sym). select{ |v| v.kind_of?(ActiveModel::Validations::LengthValidator) }. first.options[:maximum] end end end 

然后在你的模型中:

 class Comment < ActiveRecord::Base include Introspection .. end 

然后你可以做这样的事情:

 <%= form_for @comment do |f| %> <%= f.text_area(:body, :maxlength => f.object.class.max_length(:body)) %> # Or just use Comment.max_length(:body) %> <% end %>