如何获得ActiveRecord验证中配置的最大长度?

Sjo*_*ost 19 validation activerecord ruby-on-rails

鉴于一个模型:

class Person
  validates_lenght_of :name, :maximum => 50
end
Run Code Online (Sandbox Code Playgroud)

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

就像是:

Person.maximum_length_of_name
Run Code Online (Sandbox Code Playgroud)

我试过这个:

Person.validators_on(:name)
 => [#<ActiveRecord::Validations::UniquenessValidator:0x000001067a9840 @attributes=[:name], @options={:case_sensitive=>true}, @klass=Trigger(id: integer, name: string, created_at: datetime, updated_at: datetime, user_id: integer, slug: string, last_update_by: integer)>, #<ActiveModel::Validations::PresenceValidator:0x000001067a6c30 @attributes=[:name], @options={}>, #<ActiveModel::Validations::LengthValidator:0x000001067a3f08 @attributes=[:name], @options={:tokenizer=>#<Proc:0x00000101343f08@/Users/sjors/.rvm/gems/ruby-1.9.2-p0/gems/activemodel-3.0.6/lib/active_model/validations/length.rb:9 (lambda)>, :maximum=>50}>]
Run Code Online (Sandbox Code Playgroud)

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

Vas*_*ich 16

使用validators_on方法

irb(main):028:0> p Person.validators_on(:name)[0].options[:maximum]
50
=> 50
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*ana 12

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

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

我认为它也适用于Rails 3.

  • 这是一个更好的答案。对于更多的“干方式”,很容易将此方法添加为 ActiveRecord 通用方法。我在下面的回答中解释了如何。 (2认同)

Kul*_*gar 8

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


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

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

module ActiveRecord::CustomMethods
  extend ActiveSupport::Concern
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecord::CustomMethods)
Run Code Online (Sandbox Code Playgroud)

在其中添加"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
Run Code Online (Sandbox Code Playgroud)

编辑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 %>
Run Code Online (Sandbox Code Playgroud)

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


Ser*_*eev 5

更简洁:

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

使用detect{}替代select{}.firstis_a?取代class ==.
这也适用于Rails 4.1.