Rails: обеспечить капитализацию в модели?

В модели Rails, если у меня есть поле для имен собственных, как лучше всего обеспечить, чтобы они были равномерно написаны заглавными буквами, несмотря на потенциально ленивый ввод пользователей?

Допустим, в IE модель Contact, а поле Name. Независимо от того, что вводит пользователь, я хочу, чтобы слова были написаны заглавными буквами, т.е. модель преобразовывала бы следующий ввод в следующий вывод:

john doe -> John Doe
j doe -> J Doe
John doe -> John Doe
john doe jr -> John Doe Jr

Итак, вы создаете обратный вызов before_save и преобразовываете поле с помощью регулярного выражения, или вы создаете какую-то проверку или что-то другое? Я был бы очень признателен за ответы с акцентом на обоснование того, почему вы сделали бы это так или иначе, потому что это то, на чем я больше всего застрял.


person Andrew    schedule 18.04.2012    source источник


Ответы (4)


Вам нужен метод titleize. Метод capitalize обрабатывает только первый символ всей строки, поэтому "john doe".capitalize #=> "John doe", "john doe".titleize #=> "John Doe".

Что касается того, как это реализовать, вы можете использовать before_save, но мне нравится делать такие простые приготовления отдельных атрибутов с псевдоатрибутами. По сути, вы определяете метод writer для атрибута, который будет скрывать метод по умолчанию, созданный ActiveRecord. Вы по-прежнему сможете получить доступ к атрибуту с помощью метода write_attribute (документы). Таким образом, атрибут будет установлен правильно как только вы его назначите, а это означает, что даже до его сохранения вы можете быть уверены, что ваш объект находится в допустимом состоянии:

class Contact < ActiveRecord::Base

  def name=(s)
    write_attribute(:name, s.to_s.titleize) # The to_s is in case you get nil/non-string
  end

end
person tsherif    schedule 18.04.2012
comment
Я люблю это! Я не был знаком с write_attribute, но, вау, какая полезная техника! Это отлично решает проблему, всего три строки кода, и все спецификации переданы с первой попытки. Одна мелочь, в вашем примере кода self на самом деле не требуется, я это за вас исправил. - person Andrew; 18.04.2012
comment
@Андрей О, точно. Я забыл, что write_attribute это private. Странно, что родственный метод read_attribute является общедоступным. В любом случае, рад, что вам понравился совет. Удачного кодирования! - person tsherif; 18.04.2012

Более чистое исполнение @tserif выглядит следующим образом:

def name=(s)
    super s.titleize
end

Это устраняет зависимость от write_attribute и необходимость указывать имя атрибута name в пользу более примитивного метода. Я не вижу необходимости в to_s, если только вы не хотите иметь возможность назначать символ.

person YWCA Hello    schedule 01.02.2013
comment
def name=(s) super s&.titleize end - person JBlake; 25.10.2016
comment
.to_s защищает от нулей. например. irb(main):123:0> nil.titleize NoMethodError: undefined method 'titleize' for nil:NilClass - person David Hempy; 21.02.2019

Я бы предложил использовать before_save .

как в вашей модели:

before_save :capitalize_name

def capitalize_name
  self.name = self.name.split.collect(&:capitalize).join(' ') if self.name && !self.name.blank?
end
person Vik    schedule 18.04.2012

Самый важный вопрос: как вы будете отображать имена? Если это будет в сети, как я предполагаю, я бы вообще не стал обрабатывать это в модели. Самое простое решение — просто использовать css text-tansform: capitalize; для обработки заглавных букв, но если вы будете часто отображать его, вам нужно определить декоратор или вспомогательный метод, чтобы нормализовать его для вас.

def full_name
  [first_name, last_name].map { |name| name[0].upcase + name[1..-1] }.join(' ')
end

Обратите внимание, что вместо сопоставления capitalize вы просто хотите сделать первую букву заглавной. Кто-то по имени RJ или CJ, вероятно, хотел бы, чтобы буква J оставалась заглавной.

Несмотря на это, данные являются каноническими.

person Parker Selbert    schedule 18.04.2012