rails link_to image_tag button_to ruby-on-rails ruby regex validation url

ruby-on-rails - image_tag - rails 5 link_to class



Añadir http(s) a la URL si no está allí? (7)

Estoy usando esta expresión regular en mi modelo para validar una URL enviada por el usuario. No quiero obligar al usuario a escribir la parte http, pero me gustaría agregarla yo mismo si no está allí.

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

¿Alguna idea de cómo podría hacer eso? Tengo muy poca experiencia con la validación y la expresión regular ...


Prefacio, justificación y cómo se debe hacer

Odio cuando las personas cambian el modelo en un anzuelo before_validation . Luego, cuando algún día sucede que por alguna razón los modelos necesitan persistir con save (validate: false), entonces no se ejecuta ningún filtro que supuestamente se ejecutará siempre en los campos asignados. Claro, tener datos no válidos es algo que normalmente quieres evitar, pero no habría necesidad de tal opción si no se usara. Otro problema es que cada vez que preguntas desde un modelo es válido que estas modificaciones también se lleven a cabo. El hecho de que simplemente preguntarse si un modelo es válido puede hacer que el modelo que se modifique sea simplemente inesperado, quizás incluso no deseado. Si tuviera que elegir un gancho, before_save gancho before_save . Sin embargo, eso no lo hará por mí ya que proporcionamos vistas de vista previa para nuestros modelos y eso rompería los URI en la vista de vista previa ya que nunca se llamaría al gancho. Por eso, decidí que es mejor separar el concepto en un módulo o asunto y proporcionar una buena manera para que uno aplique un "parche mono" asegurando que el cambio del valor de los campos siempre se ejecuta a través de un filtro que agrega un protocolo predeterminado si es desaparecido.

El módulo

#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

En tu modelo

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"

Como una preocupación

Si por alguna razón prefieres utilizar el patrón Rails Concern, es fácil convertir el módulo anterior en un módulo de preocupación (se usa de manera exactamente similar, excepto que uses 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

PS Los enfoques anteriores se probaron con Rails 3 y Mongoid 2.
PPS Si encuentra que este método de redefinición y alias es demasiado mágico, puede optar por no anular el método, sino más bien usar el patrón de campo virtual, al igual que la contraseña (virtual, asignable en masa) y la contraseña cifrada (se mantiene persistente, no asignable en masa) y sanitize_url (virtual, asignable en masa) y url (se mantiene persistente, no asignable en masa).


La respuesta aceptada está bastante bien. Pero si el campo (url) es opcional, puede generar un error como el undefined method + para la clase nil . Lo siguiente debería resolver eso:

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


No haga esto con una expresión regular, use URI.parse para separarla y luego vea si hay un esquema en la 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

El uso de la biblioteca de URI para esto también facilita la limpieza de cualquier tontería perdida (como userinfo) que alguien pueda intentar poner en una URL.


No trataría de hacer eso en la validación, ya que no es parte de la validación.

Haga que la validación opcionalmente lo verifique; si lo arruinan será un error de validación, lo cual es bueno.

Considere usar una devolución de llamada ( after_create , after_validation , whatever) para anteponer un protocolo si ya no hay uno.

(Elegí las otras respuestas, creo que ambas son mejores que las mías. Pero aquí hay otra opción :)


Según la respuesta de mu, aquí está el código que estoy usando en mi modelo. Se ejecuta cuando: el enlace se guarda sin la necesidad de filtros de modelo. Se requiere Super para llamar al método de guardado predeterminado.

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


Usando algunas de las expresiones regulares mencionadas anteriormente, este es un método útil para anular la url predeterminada en un modelo (si su modelo ActiveRecord tiene una columna ''url'', por ejemplo)

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


Use un filtro anterior para agregarlo si no está allí:

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

Deje la validación que tiene, de esa manera si hacen un error ortográfico pueden corregir el protocolo.