I have a check of the following type
validates :callback_handle, :format => { :with => /[_0-9a-zA-Z]+/ix }, :unless => "callback.nil?"
I do not want any non 0-9, a-z A-Z characters to pass. So i set callback_handle to
"!alksjda" (note ! at the begining).
This test does not fail. What am I doing wrong?
I tried a few things on irb: This is what I got:
1.9.2-p320 :001 > a = "!askldjlad"
=> "!askldjlad"
1.9.2-p320 :002 > a =~ /[_0-9a-zA-Z]+/ix
=> 1
1.9.2-p320 :003 > a = "askldjlad"
=> "askldjlad"
1.9.2-p320 :004 > a =~ /[_0-9a-zA-Z]+/ix
=> 0
I thought it would return false or nil on failure to find the match.
Can someone tell me what is wrong here in my understanding?
EDIT:
I figured out that =~ will return position of a match.
So the question becomes How do I not allow something that has any other character to not match?
Your regular expression is still able to match, because there is at least 1 character in your string that is alpha-numeric. If you want to make sure that the entire string matches then you should define the beginning and end of the match.
Old:
a =~ /[_0-9a-zA-Z]+/ix
This is saying "match at least one of these characters somewhere in a.
New:
a =~ /\A[_0-9a-zA-Z]+\z/ix
This is saying "start at the beginning of the string, then match at least 1 of only these characters, followed by the end of the string" in a.
Your regex just asks that your string contains 1 or more valid characters ... this should fix it :
validates :callback_handle, :format => { :with => /^[_0-9a-zA-Z]+$/ix }, :unless => "callback.nil?"
Related
Rails offers the truncate method when you want to truncate text that exceeds a certain character length. This is the example provided here:
truncate("Once upon a time in a world far far away")
# => "Once upon a time in a world..."
It truncates a given text after a given :length if text is longer than :length
But I have the following example:
str = "abcdefhijklmno"
After 12 characters I want it truncated, so the above text should look like this:
abcdefhijklm...
But I tried using the truncate method and cannot get the desired result:
> str = "abcdefhijklmno"
=> "abcdefhijklmno"
> str.truncate(15)
=> "abcdefhijklmno"
> str.truncate(14)
=> "abcdefhijklmno"
> str.truncate(13)
=> "abcdefhijk..."
> str.truncate(12)
=> "abcdefhij..."
I would think that truncate(12) would do it but it truncates after 9 characters. What am I doing wrong?
argument of truncate means size of output string (with "..."):
str.truncate(13)
=> "abcdefhijk..."
str.truncate(13).size
=> 13
You can change default omission(...) by empty space if you want:
str.truncate(13, omission: '')
=> "abcdefhijklmn"
More about Rails String#truncate here.
I don't believe str.truncate will do what you want out of the box. But since it's really just an extra if statement, it's easy to write:
def trunc(str, length)
addition = str.length > length ? '...' : ''
"#{str.truncate(length, omission: '')}#{addition}"
end
Or slightly simplified, and without a Rails dependency (as mentioned by Ilya in the comments):
def trunc(str, len)
"#{str.first(len)}#{'...' if str.size > len}"
end
And the test cases:
2.2.1 :005 > s = 'abcdefghijklmno'
=> "abcdefghijklmno"
2.2.1 :006 > trunc(s, 20)
=> "abcdefghijklmno"
2.2.1 :007 > trunc(s, 15)
=> "abcdefghijklmno"
2.2.1 :008 > trunc(s, 14)
=> "abcdefghijklmn..."
2.2.1 :009 > trunc(s, 13)
=> "abcdefghijklm..."
2.2.1 :010 > trunc(s, 0)
=> "..."
2.2.1 :011 > trunc(s, 1)
=> "a..."
Basically question is about ruby syntax
class Person < ActiveRecord::Base
validates :name, presence: true #no error
end
Code Source
My 2 Questions
1
To me this code validates :name, presence: true looks a like call to a method.
How can we call a method inside class body, outside any method? I think its not possible in oops.
2
Why I am getting error in these two variations
validates (:name , presence: true) #error
or
validates (:name , {presence: true}) #error
I have added parentheses to method call, as its allowed in ruby.
First parameter is symbol and 2nd parameter is hash.
In first case I have not added curly braces to hash, as I read that if last parameter is hash you can leave curly braces, In second code I have explicitly added curly braces but still got error.
Can anyone explain this syntax.
Thanks
Edit 1
Errors
In first I am getting
product.rb:8: syntax error, unexpected ',', expecting ')' validates (:name , presence: true) # error ^
In Second I am getting
product.rb:10: syntax error, unexpected ',', expecting ')' validates (:title , {presence: true}) # error ^
1: In ruby you can call a method when defining a class:
% irb
2.2.2 :001 > class Dummy
2.2.2 :002?> puts "Making a class..."
2.2.2 :003?> def hello
2.2.2 :004?> puts "Hello"
2.2.2 :005?> end
2.2.2 :006?> end
Making a class...
=> :hello
2.2.2 :007 > d = Dummy.new
=> #<Dummy:0x000000009ebbf0>
2.2.2 :008 > d.hello
Hello
=> nil
So that's exactly what's going on.
2: You get an error because you have a space between the method name and the argument list:
% irb
2.2.3 :001 > def func(*splat)
2.2.3 :002?> puts splat.inspect
2.2.3 :003?> end
=> :func
2.2.3 :004 > func(:test, :another => :test)
[:test, {:another=>:test}]
=> nil
2.2.3 :005 > func (:test)
[:test]
=> nil
2.2.3 :006 > func (:test, :another => :test)
SyntaxError: (irb):6: syntax error, unexpected ',', expecting ')'
func (:test, :another => :test)
^
from /home/haraldei/.rvm/rubies/ruby-2.2.3/bin/irb:11:in `<main>'
The second example above, where I'm passing just one arg works because you can enclose any valid expression in parenthesis. This is not the same as an argument list. So the expression:
(:test, :another => :test)
is not a valid expression, but the parser tries to pass it as one parenthesized argument to the method.
So to summarize, both your argument lists are correct, if you remove the space between them and the function name.
The answer to your first question: "Yes it is a method" and this is also somehow the answer to your second question.
The answer to your second question is "remove the space between validates and (". When having validates (...) it will throw
syntax error, unexpected ',', expecting ')' (SyntaxError)
validates (:name , presence: true)
validates is a method, and if using parentheses you mustn't use spaces.
I have two numbers of different length:
"103" and "11"
In irb:
2.1.1 :005 > "11" > "103"
=> true
2.1.1 :006 > "11" < "103"
=> false
Why does this happen? I understand I can to a .to_i for each string, but if this is a rails query where the column type is string, anything I can do about this?
Strings are sorted lexicographically which means that "1" comes after "0", and "103" comes before "11", and before "1122344", and before "1abc".
You cannot compare strings as if they were numbers, you need to parse them as numbers before you can do that.
The only way I can think of, is to make sure they are padded with enough zeroes before they are turned into a string: "000103", "000011"...
Strings are being compared character by character. Hence '11' > '103' execution stops on a second character and returns true, since '1'.chr > '0'.chr
They are strings. And they are compared by String#ord value.
So '1'.ord # => 49 and '0'.ord # => 48. That is why
'11' > '10' # => true
# and
'11' > '100' # => true
as well as
'b' > 'a' # => true
'a'.ord # => 97
'b'.ord # => 98
# and
'b' > 'aaaaa' # => still true
Context
I have Rails (4.0.1 + Ruby 2.0.0) connected to a PostgreSQL database filled with strings like "€ 289,95". The values have been scraped from a website using Nokogiri. I want to convert the strings to floating points.
What I've tried
Rails console:
listing = Listing.find(1)
=> #<Listing id: 1, title: #, subtitle: #, name: #, price: "€ 289,95", url: #, created_at: #, updated_at: #>
listing_price = listing.price
=> "€ 289,95"
listing_price_1 = listing_price.gsub(/,/, ".")
=> "€ 289.95"
listing_price_2 = listing_price_1.gsub(/€\s/, "")
=> "€ 289.95"
listing_price_3 = listing_price_2.to_f
=> 0.0
Problem
The code works in irb but doesn't work in the rails console.
What I want to know
How to convert a string "€ 289,95" to a float "289.95" in Rails?
The step where your technique is failing is when trying to strip away € and the space from € 289.95 with the regexp /€\s/, but this is not matching, leaving the string unchanged.
The space character in € 289,95 is probably a non-breaking space (U+00A0) rather than a “normal” space, and would be used in the web page so that the € and the value are not separated.
In Ruby the non-breaking space is not matched by \s in a regexp, so your call to gsub doesn’t replace anything:
2.0.0p353 :001 > s = "€\u00a0289.95"
=> "€ 289.95"
2.0.0p353 :002 > s.gsub(/€\s/, "")
=> "€ 289.95"
Non-breaking space is matched by the POSIX bracket expression [[:space:]], or by the character property \{Blank}:
2.0.0p353 :003 > s.gsub /€[[:space:]]/, ""
=> "289.95"
2.0.0p353 :004 > s.gsub /€\p{Blank}/, ""
=> "289.95"
So if you wanted a more specific regexp than in the other answer you could use one of these.
"€ 289,95".sub(/\A\D+/, "").sub(",", ".").to_f
# => 289.95
listing.price.delete('€ ') # => "289,95"
listing.price.delete('€ ').tr(',', '.') # => "289.95"
listing.price.delete('€ ').tr(',', '.').to_f # => 289.95
String's 'delete' method is good for removing all occurrences of the target strings.
and 'tr' method takes a string of characters to search for, and a string of characters used to replace them.
Better probably than the accepted answer is:
"€ 289,95"[/[\d,.]+/].tr ',', '.'
I have a string like
"car\"
which I will be storing in postgres db. I want to remove the backslash from the string before saving. Is there a way I can do that in ruby or in postgres? When I try to remove it in ruby, it considers the quote after the backslash as an escape character.
See following code:
1.9.3p125 :022 > s = "cat\\"
=> "cat\\"
1.9.3p125 :023 > puts s
cat\
=> nil
1.9.3p125 :024 > s.chomp("\\")
=> "cat"
1.9.3p125 :025 >
People don't do this much, but Ruby's String class supports:
irb(main):002:0> str = 'car\\'
=> "car\\"
irb(main):003:0> str[/\\$/] = ''
=> ""
irb(main):004:0> str
=> "car"
It's a conditional search for a trailing '\', and replacement with an empty string.
To remove a trailing backslash:
"car\\".gsub!(/\\$/, "")
Note that the backslash has to be escaped itself with a backslash.
puts '"car\"'.gsub(/\\(")?$/, '\1')
that will do it,
but, is the trailing slash always at the en followed by a quote?
See what says the
str.dump
operation, and then try to operate on that.