I want to validate a form input so that http:// and www is not allowed. Which REGEX would work?
For example:
Allowed
google.com
NOT Allowed
www.google.com
http://google.com
http://www.google.com
MODEL
VALID_DOMAIN_REGEX = ???
validates :domain, format: { with: VALID_DOMAIN_REGEX }
Since http:// contains so many forward slashes, this would be a good use for Ruby's %r{} regex literal syntax.
def has_forbidden_prefix?(string)
string =~ %r{^(http://|www)}
end
This will return nil, falsy, if the string does not start with http:// or www.
It will return 0, truthy (the offset of the first match) if the string does.
You can use validate :some_method_name to call a custom validation method in the model, I would structure it as follows
model MyThing
validate :no_forbidden_prefix
private
def has_forbidden_prefix?(string)
string =~ %r{^(http://|www)}
end
def no_forbidden_prefix
if has_forbidden_prefix?(uri)
errors.add :domain, 'The URI cannot start with "http://" or "www"'
end
end
end
This should do it for you:
/^[http\:\/\/|www].*/
For example:
1.9.2p320 :007 > "http://www.google.de".match /^[http\:\/\/|www].*/
=> #<MatchData "http://www.google.de">
1.9.2p320 :008 > "www.google.de".match /^[http\:\/\/|www].*/
=> #<MatchData "www.google.de">
1.9.2p320 :009 > "google.de".match /^[http\:\/\/|www].*/
=> nil
So it doenst match if its valid for your purposes...
Related
I have two customs validations :
def validate_email
regexp = "[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+"
if sleep_email.present? && !sleep_email.match(regexp)
errors.add(:sleep_email, "l'email indiqué semble ne pas avoir le bon format")
end
end
def validate_website
regexp = "(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?"
if website.present? && !website.match(regexp)
errors.add(:website, "l'url de votre site web doit avoir la forme de http://votresite.com")
end
end
But yo#yo and http://website are valids. What's wrong ?
You're building regexes using strings. Strings and regexes have different quoting. You're effectively double escaping. Things like \. are turned into a plain ..
# This results in the regex /a.c/
p "abc".match?("a\.c") # true
# This results in the desired regex /a\.c/
p "abc".match?("a\\.c") # true
# This avoids the string escaping entirely.
p "abc".match?(%r{a\.c}) # false
To avoid this double escaping, use /.../ or %r{...} to create regexes.
Don't try to validate email with a regex. Instead, use the validates_email_format_of gem which provides a proper validator you can use on any attribute.
validates :sleep_email, presence: true, email_format: true
If you want to see how to fully validate an email address, look at the source.
Your URL regex does work.
regexp = "(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?"
p "http://website".match?(regexp) # true
http://website is valid URL syntax. It's not URL's job to check the validity of the host.
If you also want to validate parts of the URL your regex will get increasingly complex. Instead, parse the URL with URI and then check its individual pieces as you like.
Here's a custom validator I whipped up which parse the URI, checks it's an allowed scheme, and does a very rudimentary check on the host.
class UrlValidator < ActiveModel::EachValidator
ALLOWED_SCHEMES = ['http', 'https']
private def allowed_schemes
options[:allowed_schemes] || ALLOWED_SCHEMES
end
def validates_each(record, attribute, value)
uri = URI(value)
if !allowed_schemes.include?(uri.scheme)
record.errors.add(attribute, :scheme_not_allowed, message: "Scheme #{uri.scheme} is not allowed")
end
# Has to have at least xxx.yyy
# This is a pretty sloppy host check.
if !uri.host.match?(/\w+\.\w+/)
record.errors.add(attribute, :host_not_allowed, message: "Host #{uri.host} is not allowed")
end
rescue URI::Error
record.errors.add(attribute, :not_a_uri)
end
end
validates :website, url: true
If you wanted to allow other schemes, like ftp...
validates :website, url: { allowed_schemes: ['http', 'https', 'ftp'] }
If you wanted true domain validation, you could add a DNS lookup.
begin
Resolv::DNS.open do |dns|
dns.getaddress(uri.host) }
end
rescue Resolv::ResolvError
record.errors.add(attribute, :invalid_host, { message: "#{uri.host} could not be resolved" }
end
However, this lookup has a performance impact.
The standard email regex (RFC 5322 Official Standard) to use is:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
As for the website URL, use this one. The URL will only be valid if the TLD (.com, .net, etc.) is included.
^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$
I have the code as below, as I understand, it only handles when a.blank? is true. But [" "].blank? is false. Why it cannot pass validation
class Demo < CouchRest::Model::Base
collection_of :subdemos
validate :ensure_subdemos
def ensure_subdemos
errors.add(:demo, "must include subdemos.") if subdemos.blank?
end
end
if I do demo.update_attributes(:subdemo_ids => [" "]), why it cannot pass validation?? Can anyone go through the process for me??
You need to use actual IDs. White space is blank:
-> % rails c
Loading development environment (Rails 4.2.3)
Frame number: 0/5
[1] pry(main)> " ".blank?
true
[2] pry(main)>
If you add data there it should pass validation:
demo.update_attributes(:subdemo_ids => [1,2,3])
If you want to allow white space or an empty array, try:
def ensure_subdemos
errors.add(:demo, "must include subdemos.") if subdemos.nil?
end
I'm not sure if I'm even asking the right question. I may be approaching the problem incorrectly, but basically I have this situation here:
obj = get_user(params)
obj.profile => {:name => "John D", :age => 40, :sex => "male"} #Has to be of class Hash
obj.profile.name => "John D"
obj.profile[:name] => "John D"
obj.profile.job => nil
So basically, I have to satisfy all of these conditions and I'm not sure exactly how to even approach this (I just learned Ruby today).
Note the dot notation for accessing the inner variables, otherwise I would have just had profile be a hash of symbols. So I've tried two methods, which only sort of get me there
Method 1: Make profile an OpenStruct
So this allows me to access name, age and sex using the dot notation, and it automatically returns nil if a key doesn't exist, however obj.profile is of the type OpenStruct instead of Hash
Method 2: Make profile its own class
With this I set them as instance variables, and I can use method_missing to return nil if they don't exist. But, I again run into the issue of obj.profile not being the correct type/class
Is there something I'm missing? Is there a way to maybe differentiate between
obj.profile
obj.profile.name
in the getter function and return either a hash or otherwise?
Can I change what is returned by my custom class for profile, so it returns a Hash instead?
I've even tried checking the args and **kwargs in the get function for obj.profile and neither of them seem to help, or populate if I call obj.profile.something
If it absolutely has to be a Hash:
require 'pp'
module JSHash
refine Hash do
def method_missing(name, *args, &block)
if !args.empty? || block
super(name, *args, &block)
else
self[name]
end
end
end
end
using JSHash
profile = {:name => "John D", :age => 40, :sex => "male"}
pp profile.name # "John D"
pp profile[:name] # "John D"
pp profile.job # nil
pp profile.class # Hash
But still better not to be a Hash, unless it absolutely needs to:
require 'pp'
class Profile < Hash
def initialize(hash)
self.merge!(hash)
end
def method_missing(name, *args, &block)
if !args.empty? || block
super(name, *args, &block)
else
self[name]
end
end
end
profile = Profile.new({:name => "John D", :age => 40, :sex => "male"})
pp profile.name
pp profile[:name]
pp profile.job
For only a few hash keys, you can easily define singleton methods like so:
def define_getters(hash)
hash.instance_eval do
def name
get_val(__method__)
end
def job
get_val(__method__)
end
def get_val(key)
self[key.to_sym]
end
end
end
profile = person.profile #=> {name: "John Doe", age: 40, gender: "M"}
define_getters(profile)
person.profile.name #=> "John Doe"
person.profile.job #=> nil
Reflects changed values as well (in case you were wondering):
person.profile[:name] = "Ralph Lauren"
person.profile.name #=> "Ralph Lauren"
With this approach, you won't have to override method_missing, create new classes inheriting from Hash, or monkey-patch the Hash class.
However, to be able to access unknown keys through method-calls and return nil instead of errors, you'll have to involve method_missing.
This Hash override will accomplish what you're trying to do. All you need to do is include it with one of your class files that you're already loading.
class Hash
def method_missing(*args)
if args.size == 1
self[args[0].to_sym]
else
self[args[0][0..-2].to_sym] = args[1] # last char is chopped because the equal sign is included in the string, print out args[0] to see for yourself
end
end
end
See the following IRB output to confirm:
1.9.3-p194 :001 > test_hash = {test: "testing"}
=> {:test=>"testing"}
1.9.3-p194 :002 > test_hash.test
=> "testing"
1.9.3-p194 :003 > test_hash[:test]
=> "testing"
1.9.3-p194 :004 > test_hash.should_return_nil
=> nil
1.9.3-p194 :005 > test_hash.test = "hello"
=> "hello"
1.9.3-p194 :006 > test_hash[:test]
=> "hello"
1.9.3-p194 :007 > test_hash[:test] = "success"
=> "success"
1.9.3-p194 :008 > test_hash.test
=> "success"
1.9.3-p194 :009 > test_hash.some_new_key = "some value"
=> "some value"
1.9.3-p194 :011 > test_hash[:some_new_key]
=> "some value"
Let's say I got a regular expression like this:
/\b[A-Z0-9._%a-zöäüÖÄÜ\-]+#(?:[A-Z0-9a-zöüäÖÜÄ\-]+\.)+[A-Za-z]{2,4}\z/
How can I check via Ruby/RoR if this string is a valid regular expression?
If it doesn't raise errors, it's a valid regex. :)
def valid_regex?(str)
Regexp.new(str)
true
rescue
false
end
valid_regex?('[a-b]') # => true
valid_regex?('[[a-b]') # => false
For the ActionDispatch::Routing::Mapper::Base module, the match method is defined like this:
match(path, options=nil)
One thing I find challenging in the Rails documentation is that it doesn't tell me what the type of some of these parameters are. So let's look at some of the examples:
match ':controller/:action/:id'
Here, path is a string.
match 'songs/*category/:title' => 'songs#show'
Here, it's a hash. Or is it a string still? I'm not sure how to interpret this syntax. Is it:
{ match 'songs/*category/:title' => 'songs#show' }
where match 'songs/*category/:title' is the key and 'songs#show' is the value? Or:
match {'songs/*category/:title' => 'songs#show'}
where the match method is being called with a hash as the first argument?
It's either a string or a hash. And it's the second one:
match {'songs/*category/:title' => 'songs#show'}
But the hash is actually an argument, so more correctly it would be:
match({'songs/*category/:title' => 'songs#show'})
You can try that yourself with a mock method in the irb:
irb(main):005:0> def match(foo)
irb(main):006:1> puts foo
irb(main):007:1> end
=> nil
irb(main):008:0> match "somestring"
somestring
=> nil
irb(main):009:0> match :has => "hash"
{:has=>"hash"}
=> nil
It is a hash as in
match({'songs/*category/:title' => 'songs#show'})
At the final argument position, you can omit the {}. But you cannot write it like
match {'songs/*category/:title' => 'songs#show'}
because the {} will be interpreted as a block, and will cause a syntax error without (), which explicitly indicates that it is an argument.
For match ':controller/:action/:id', `path is a String.
For match 'songs/*category/:title' => 'songs#show', path is a Hash:
1.9.3p125 :001 > def match(path, options=nil)
1.9.3p125 :002?> puts path
1.9.3p125 :003?> puts options
1.9.3p125 :004?> end
=> nil
1.9.3p125 :005 > match 'foo' => 'bar'
{"foo"=>"bar"}
=> nil