Дата строки Ruby to_date с попыткой дает неверную дату

Я хочу попытаться получить дату из параметров в формате даты, и если это не так, я хотел бы назначить ее дате с сегодняшнего года.

Это то, что я пробовал.

valid_until = params[:valid_until].try(:to_date) || Date.today.next_year

Метод try крут, потому что если дата :valid_until равна нулю, он просто вернет nil. Однако я обнаружил, что если у кого-то есть недопустимая дата, например «4790224374», он вернет ArgumentError как недопустимую дату. дата :valid_until все равно будет сравниваться с to_date.

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

ИЗМЕНИТЬ:

Вы можете прочитать о Попробуйте здесь.

Вы можете прочитать о to_date здесь


person TheLegend    schedule 30.09.2014    source источник
comment
Вы могли бы поставить rescue вместо || и, возможно, убрать try? Это было бы довольно аккуратно, но я думаю, недостатком является то, что все исключения будут перехвачены.   -  person Sam Starling    schedule 30.09.2014
comment
Да что я думал. это немного сложно. это может очень быстро запутаться, я потратил последнее время на просмотр нескольких идей, но все, похоже, добавили несколько строк.   -  person TheLegend    schedule 30.09.2014
comment
когда вы не используете ядро ​​ruby, не могли бы вы включить библиотеки, которые вы используете, чтобы помочь тем, кто хотел бы помочь :)   -  person Jeff Price    schedule 30.09.2014
comment
Извините, реальная история, которую я отредактировал для тех, кто их ищет :)   -  person TheLegend    schedule 30.09.2014
comment
реальная история я знал где их найти, но не все знают рельсы :)   -  person Jeff Price    schedule 30.09.2014


Ответы (2)


Вы неправильно используете Object.try. Этот метод предназначен для тихой ошибки, если метод не существует для объекта. В этом случае метод есть (так он называется) и этот метод не работает.

Это не предназначено для замены блока try/rescue. Возможная реализация ниже.

def expiration_date(a_string)
  Date.parse(a_string)
rescue
  Date.today.next_year
end

valid_until = expiration_date(params[:valid_until])
person Jeff Price    schedule 30.09.2014

Если это не какой-то код-гольф, я бы не стал пытаться втиснуть как можно больше логики в один лайнер. Кроме того, вы, вероятно, хотите, чтобы ваши контроллеры были максимально компактными. Почему бы не использовать какое-то здравое чутье ОО, которое говорит вам: «Если я не могу понять логику здесь, может быть, мне следует извлечь ее в отдельный метод или класс»? Ф.и.

# app/services/expirer.rb
class AccountExpirer
  def self.expiration_date(user_input)
    return Date.today.next_year unless user_input.present?
    begin
      Date.parse(user_input)
    rescue ArgumentError
      Date.today.next_year
    end
  end
end

# some controller
valid_until = AccountExpirer.expiration_date(params[:valid_until])

Но если вам нужно сообщить пользователю, что он ввел неверные данные, я бы не стал останавливаться на достигнутом. Вы можете расширить свой класс с помощью ActiveModel::Model (http://api.rubyonrails.org/classes/ActiveModel/Model.html), что позволит вам писать правильные проверки и использовать их в своих формах (точно так же, как модель AR).

person Ernest    schedule 30.09.2014
comment
Эрнест, мне любопытны ваш метод и мой. Есть ли какая-то причина, по которой вы решили перехватывать только ArgumentErrors при спасении и блокировать nil (что приведет к TypeError) вместо того, чтобы просто спасать все? - person Jeff Price; 30.09.2014
comment
@JeffPrice Я бы вообще не стал начинать / спасать, если честно. Но вы не предоставили никакой информации о том, применяете ли вы формат даты или какие-либо другие ожидания, поэтому моей первой мыслью было использовать Date.parse и перехватить исключение, которое оно выдает (Date.parse на недопустимую дату выдаст ArgumenError вместо этого of, fi Date:InvalidDateError — это потому, что этот метод не предназначен для проверки). Моя точка зрения была другой, то есть такая логика не должна оставаться в контроллере. - person Ernest; 30.09.2014
comment
Этот контроллер обрабатывает загрузку и не имеет модели для запуска каких-либо проверок. Но вы абсолютно правы. это плохая практика, когда захваченные данные проверяются на уровне контроллера, извлечение этого поведения в службу также является хорошей идеей. Спасибо! - person TheLegend; 30.09.2014
comment
@TheLegend Вы можете создать модель (вообще не подключенную к базе данных), включив ActiveModel в любой простой класс. - person Ernest; 30.09.2014