Как получить максимальную длину, настроенную при проверке ActiveRecord? - PullRequest
19 голосов
/ 16 мая 2011

Учитывая модель:

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

У меня есть некоторый код представления, который показывает обратный отсчет и обеспечивает этот максимум. Однако я жестко закодировал число 50 в этот код представления. Есть ли способ извлечь этот номер из модели?

Что-то вроде:

Person.maximum_length_of_name

Я пробовал это:

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}>]

Информация там, но я не знаю, как ее извлечь:

Ответы [ 8 ]

16 голосов
/ 16 мая 2011

Использование validators_on метод

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

Как упоминал @Max Williams, он работает только на Rails 3

12 голосов
/ 04 октября 2012

Проблема с ответом @nash заключается в том, что валидаторы не владеют определенным заказом.Я выяснил, как сделать то же самое, просто добавив немного кода, но в каком-то более безопасном режиме (потому что вы можете добавить больше валидаторов позже и нарушить порядок их получения):

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

Я думаюон работает только для Rails 3.

8 голосов
/ 21 ноября 2012

[Редактировать 2017-01-17] Осторожно Мой ответ старый (2012) и был для Rails 3. Он может не работать / быть идеальным для новых версий Rails.


Просто для того, чтобы привнести немного СУХОГО духа, вы можете создать универсальный метод класса, чтобы получить максимальное значение "length_validator" для любого атрибута, например, так:

Создайте модуль вкаталог lib и расширение его ActiveSupport :: Concern :

module ActiveRecord::CustomMethods
  extend ActiveSupport::Concern
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecord::CustomMethods)

Добавьте в него «модуль 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: Конфигурация

Вы также должны будете добавить требование в один из ваших инициализаторов.

Например, вот мои конфигурации:

  1. Я поместил свой файл в lib / modules / active_record / extensions.
  2. Я добавил это вmy autoload_paths: config.autoload_paths += %W(#{config.root}/lib/modules) Примечание: это не обязательно, но рекомендуется, если вы хотите поместить туда некоторые из ваших пользовательских классов и модулей, которые вы используете в своих приложениях.
  3. В одномиз моих инициализаторов (config / initializers / custom.rb) я добавил эту строку: require "active_record/extensions"

И это должно быть сделано!Перезагрузите сервер и затем ...

END EDIT 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 %>

Я надеюсь, что это поможет другим!:) Конечно, вы можете настроить метод так, как вы хотите, добавить опции и делать модные вещи.; -)

5 голосов
/ 10 февраля 2015

Более кратко:

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

Использует detect{} вместо select{}.first и is_a? вместо class ==.
Это также работает с Rails 4.1.

2 голосов
/ 15 августа 2017

Еще более динамичным, чем ответ Кулгара, было бы использовать что-то вроде этого:

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

Таким образом вы можете заказать валидаторы внутри модели так, как вы хотите .

Используйте его в качестве помощника 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)
0 голосов
/ 08 апреля 2019

Это косвенный ответ, но это альтернативное решение, на тот случай, если оно может оказаться полезным для любого.

Альтернативное решение 1

class Person
  MAX_LENGTHS = {
    name: 50,
    # email: 30, etc...
  }.freeze

  validates :name, length: { maximum: MAX_LENGTHS.fetch(:name) }
end

# usage example in view file
<%= Person.MAX_LENGTHS.fetch(:name) %>

Альтернативное решение 2

... или если вы предпочитаете однострочные, или не использовать хеш-константу

class Person
  validates :name, length: { maximum: (MAX_NAME_LENGTH = 50) }
  # validates :password, length: {
  #   minimum: (MIN_PASSWORD_LENGTH = 8),
  #   maximum: (MAX_PASSWORD_LENGTH = 70)
  # }
  # ... etc
end

# usage example in view file
<%= Person.MAX_NAME_LENGTH %>
0 голосов
/ 07 февраля 2015

Ответ Кулгара хорош и, возможно, идеален.Вот более простой способ сделать это для Rails 4, который не требует изменения какой-либо конфигурации, с недостатком, заключающимся в том, что вы должны добавить строку включения для каждой модели, которая хочет его использовать..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 %>
0 голосов
/ 16 мая 2011

Если вы в рельсах 2, это не легко. Я помню, как пробовал это раньше и не ушел далеко. Вы можете получить доступ к объектам проверки, но они не перечисляют, для какого поля они предназначены, и которые мне показались очень странными. Люди сделали плагины для этого (то есть, чтобы проверить или отразить проверки объекта AR), такие как https://github.com/redinger/validation_reflection

...