Подтвердить что ты не робот

Добавить http (s) в URL, если это не так?

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

validates :url, :format => { :with => /^((http|https):\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+).[a-z]{2,5}(:[0-9]{1,5})?(\/.)?$/ix, :message => " is not valid" }

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

4b9b3361

Ответ 1

Используйте фильтр before, чтобы добавить его, если он отсутствует:

before_validation :smart_add_url_protocol

protected

def smart_add_url_protocol
  unless self.url[/\Ahttp:\/\//] || self.url[/\Ahttps:\/\//]
    self.url = "http://#{self.url}"
  end
end

Оставьте проверку, которая у вас есть, таким образом, если они делают опечатку, они могут исправить протокол.

Ответ 2

Не делайте этого с помощью регулярного выражения, используйте URI.parse, чтобы разделить его, а затем посмотреть, есть ли схема по URL-адресу

u = URI.parse('/pancakes')
if(!u.scheme)
    # prepend http:// and try again
elsif(%w{http https}.include?(u.scheme))
    # you're okay
else
    # you've been give some other kind of
    # URL and might want to complain about it
end

Использование библиотеки URI для этого также упрощает очистку любой блуждающей бессмыслицы (например, userinfo), которую кто-то может попытаться поместить в URL-адрес.

Ответ 3

Принятый ответ вполне в порядке. Но если поле (url) является необязательным, оно может вызвать ошибку, например undefined method + для nil. Следующее должно решить следующее:

def smart_add_url_protocol
  if self.url && !url_protocol_present?
    self.url = "http://#{self.url}"
  end
end

def url_protocol_present?
  self.url[/\Ahttp:\/\//] || self.url[/\Ahttps:\/\//]
end

Ответ 4

Основываясь на ответе mu, вот код, который я использую в своей модели. Это выполняется, когда: ссылка сохраняется без использования фильтров модели. Для вызова метода сохранения по умолчанию требуется Super.

def link=(_link)
    u=URI.parse(_link)

    if (!u.scheme)
        link = "http://" + _link
    else
        link = _link
    end
    super(link)
end

Ответ 5

Предисловие, обоснование и то, как это должно быть сделано

Я ненавижу, когда люди меняют модель в before_validation. Затем, когда когда-нибудь случается, что по какой-то причине модели нужно сохранять с помощью save (validate: false), тогда какой-то фильтр, который, как предполагается, всегда запускается в назначенных полях, не запускается. Конечно, наличие недопустимых данных обычно является чем-то, чего вы хотите избежать, но не было бы необходимости в таком варианте, если он не использовался. Другая проблема заключается в том, что каждый раз, когда вы спрашиваете у модели, действительно ли эти изменения также имеют место. Тот факт, что просто спрашивает, действительна ли модель, может привести к тому, что модифицируемая модель просто неожиданна, возможно, даже нежелательна. Там, если мне придется выбирать крючок, я бы пошел за крюком before_save. Тем не менее, это не будет сделано для меня, поскольку мы предоставляем предварительные просмотры для наших моделей, и это нарушит URI в представлении предварительного просмотра, так как крючок никогда не будет вызван. Там для меня я решил лучше отделить концепцию до модуля или проблемы и предоставить хороший способ применить "патч обезьяны", гарантирующий, что изменение значения полей всегда выполняется через фильтр, который добавляет протокол по умолчанию, если он отсутствует.

Модуль

#app/models/helpers/uri_field.rb
module Helpers::URIField
  def ensure_valid_protocol_in_uri(field, default_protocol = "http", protocols_matcher="https?")
    alias_method "original_#{field}=", "#{field}="
    define_method "#{field}=" do |new_uri|
      if "#{field}_changed?"
        if new_uri.present? and not new_uri =~ /^#{protocols_matcher}:\/\//
          new_uri = "#{default_protocol}://#{new_uri}"
        end
        self.send("original_#{field}=", new_uri)
      end
    end
  end
end

В вашей модели

extend Helpers::URIField
ensure_valid_protocol_in_uri :url
#Should you wish to default to https or support other protocols e.g. ftp, it is
#easy to extend this solution to cover those cases as well
#e.g. with something like this
#ensure_valid_protocol_in_uri :url, "https", "https?|ftp"

В качестве беспокойства

Если по какой-то причине вы предпочитаете использовать шаблон Rails Concern, легко преобразовать вышеуказанный модуль в модуль беспокойства (он используется точно так же, за исключением того, что вы используете include Concerns::URIField:

#app/models/concerns/uri_field.rb
module Concerns::URIField
  extend ActiveSupport::Concern

  included do
    def self.ensure_valid_protocol_in_uri(field, default_protocol = "http", protocols_matcher="https?")
      alias_method "original_#{field}=", "#{field}="
      define_method "#{field}=" do |new_uri|
        if "#{field}_changed?"
          if new_uri.present? and not new_uri =~ /^#{protocols_matcher}:\/\//
            new_uri = "#{default_protocol}://#{new_uri}"
          end
          self.send("original_#{field}=", new_uri)
        end
      end
    end
  end
end

P.S. Вышеуказанные подходы были протестированы с помощью Rails 3 и Mongoid 2.
PPS Если вы обнаружите, что переопределение этого метода и псевдонижение слишком волшебны, вы можете отказаться от переопределения метода, а скорее использовать шаблон виртуального поля, подобно паролю (виртуальный, назначаемый по массе) и encrypted_password (сохраняется, нецелесообразно назначать) и использовать sanitize_url (виртуальный, назначаемый по массе) и url (сохраняется, не назначается массой).

Ответ 6

Я бы не попытался сделать это в валидации, так как это не является частью проверки.

Проверить правильность проверки; если они ввернут его, это будет ошибка проверки, что хорошо.

Рассмотрите возможность использования обратного вызова (after_create, after_validation, что угодно) для добавления протокола, если его уже нет.

(Я проголосовал за другие ответы, я думаю, что они оба лучше моих. Но вот еще один вариант:)

Ответ 7

Используя некоторые из вышеупомянутых регулярных выражений, вот удобный метод для переопределения url по умолчанию для модели (если, например, ваша модель ActiveRecord имеет столбец "url" )

def url
  _url = read_attribute(:url).try(:downcase)
  if(_url.present?)
    unless _url[/\Ahttp:\/\//] || _url[/\Ahttps:\/\//]
      _url = "http://#{_url}"
    end
  end
_url
end