I have an Application model which has app_id and secret_key fields. What is the best way to generate unique app_ids?
I can use ActiveSupport:SecureRandom.hex(16) to generate an 32-char alpha-numeric string and there will probably be no other string like it. If done in this manner, should I also do a database check to see if there is a duplicate app_id or is this step unnecessary since the likelihood of that is infinitesimally small?
Or is there a better method?
Thanks!
Tim
I would always double check, just to be sure. Put a unique index on app_id and it's all set. It's hard to guarantee uniqueness
However, you could build a string that is guaranteed to be unique.
string = ActiveSupport::SecureRandom.hex(16)
append = #app.id.to_s
string = string.slice(0, string.length - append.length) + append
So the first part is random, but it always ends with the database id column, which would have to be unique.
There are also likely variations of this that keep the random looking structure, e.g. using a Caesar Cipher or a simple numeric to alphabetic cipher.
I would check first.
Here's some code I've seen in devise used when generating a unique token (modified for your example):
loop do
token = ActiveSupport::SecureRandom.hex 16
break token unless find(:first, :token => token)
end
Line 162:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/authenticatable.rb
Related
I want to create ticket number by serial number, eg. T-0001, T-0002, T-0003,
for ruby on rails project. How to make this?
Admission.transaction do
cus = #admission.customer
cus.inpatient_id = cus.inpatient_id || "I-%.6d" % cus.id
cus.save
end
Most rails servers are multi-threaded. Meaning many requests will be processed in parallel. You can imagine two processes trying to create a new serial number at the same point in time - duplicate ticket numbers! - not what we expect for sure.
It is better we delegate this task of creating ids to the database itself. So instead of the default auto-increment ids (1,2,3,4...), we will tell database to create ids in this format (T-0001, T-0002, ...). This can be achieved using custom sequences. I am assuming postgres database here, but should be same for mysql.
First create sequence
CREATE SEQUENCE ticket_seq;
But sequences don't allow strings so we convert them to strings and format them:
SELECT 'T-'||to_char(nextval('ticket_seq'), 'FM0000');
This will return values like T-0001, T-0002 ...
Note: We have just created a sequence, you need to tell database to use this sequence instead.
Check: https://stackoverflow.com/a/10736871/3507206
here is just sample to generate your required formatted series on range:
> (0..5).map{|e| "T-#{e.to_s.rjust(4, "0")}"}
#=> ["T-0000", "T-0001", "T-0002", "T-0003", "T-0004", "T-0005"]
If you are using PG / MySQL you can use object's id for unique number (ID- primary key is always serialize and unique)
UPDATE: as per OP's comment:
Admission.transaction do
cus = #admission.customer
cus.inpatient_id = cus.inpatient_id || "T-#{cus.id.to_s.rjust(4, "0")}"
cus.save
end
I have a method in a model with Rails. This is the code:
def ensure_appropriate_age
age = match[:age]
if age[/\d/].to_i > 18
current_user.update age: age[/\d/].to_i
else
%{We could not proceed, sorry.}
end
end
I'm taking the input of what the user types and if it contains a number, verify that it is greater than 18 to store it.
I'll enter my age like so: im 24. I still get false, and I can see in the database it's only storing the number "2".
What is required to make this work?
You have to use \d+ to match multiple digits; \d only matches a single digit in a number.
You can also capture the value of the regex into a variable, so that you don't have to evaluate it twice, like shown:
def ensure_appropriate_age(age_string)
age = age_string[/\d+/].to_i
if age > 18
current_user.update age: age
else
%{We could not proceed, sorry.}
end
end
It's good to step back a second, and ask yourself why do you need to extract the age from a string here. What else are you holding in it? If more information is present, build a quick parser in the caller or initializer to partition the data, and cast to the proper types.
The trick is: once the age is isolated from the other information, casting is straightforward.
user_data = "John Smith 22"
#name, #surname, age_str = user_data.split(" ")
#age = age_str.to_i
Then just use your function. Ruby style guides also advise you to use quotes "..."rather than
%{} unless needed (i.e. your string is full of quotes).
If you push yourself to keep it simple whenever you can, you will find your code easier to read and faster to write and debug. There's plenty cases in which regex(es?) are the simplest way to go, but until you get there don't sweat it :)
I have an API that has a database with UPC-12 values in it. Sometimes API calls will come in with UPC-10 codes. My db upc column is bigint, so it removes the leading 0 on a UPC-12 value. That leaves the last digit as a wildcard when comparing to UPC-10.
I'd like to be able to check a UPC-10 value against records in the db to see if there's a match. Since I can't use LIKE, how do I do that?
The goal is to do something like:
def self.pull_product(upc)
upc_string = upc.to_s
if upc_string.length == 10
# product = Product.where... use a wildcard to try and match to existing record
else
product = Product.find_by_upc(upc)
end
end
This Rails 4 and Postgresql.
Just to clarify:
I might have a UPC-10 api call with a upc param like: 7618600002. My database has the UPC-12 equivalent: 76186000023. So if I just query for the param in the api call, I'll get nil.
I need a way to match the the UPC-10 param against my UPC-12 value in the database.
You need to use SQL like this:
upc between upc_string::int*10 and upc_string::int*10+9
I have no idea how to code it in Rails though.
How do one code an email, say, alibaba#gmail.com to a***a#g***l.c*m in ruby on rails?
I found this when I tried to recover my password to my gmail account.
If you have the email already split into address and domain this is much easier. But to do that its simply:
email = 'alibaba#gmail.com'
address, domain = email.split('#')
If you don't care about the character count between the first and last of each token:
"#{address[0]}***#{address[-1]}"
for the a**a before the # and similar can be done for the domain but using split on the . character:
working_domain = domain.split('.')
"#{working_domain[0][0]}***#{working_domain[0][-1]}.#{working_domain[1][0]}*#{working_domain[1][-1]}"
That's a pretty ugly way to do it and its not very DRY and doesnt care about character counts. You should be able to encapsulate all of this into a function or 3 and make this simpler to use.
From the example you give in the question ("alibaba#gmail.com" => "a***a#g***l.c*m"), it appears you don't need the number of *'s to match the number of replaced characters. If that's the case, you can solve this with a simple regex substitution, no splitting or parsing of the address necessary:
email = 'alibaba#gmail.com'
email.gsub(/(?<=[\w\d])[\w\d]+(?=[\w\d])/, "**")
# => "a**a#g**l.c**m"
Breaking down that regex, just for clarity: [\w\d]+ matches strings of alphanumeric characters, excluding one alphanumeric to the left ((?<=[\w\d])) and another to the right ((?=[\w\d])) of each matched group, and replaces each match with "**".
I hope this helps.
I need to store a regular expression related to other fields in a database table with ActiveRecord.
I found the to_s method in Regexp class which states
Returns a string containing the regular expression and its options
(using the (?opts:source) notation. This string can be fed back in to
Regexp::new to a regular expression with the same semantics as the
original. (However, Regexp#== may not return true when comparing the
two, as the source of the regular expression itself may differ, as the
example shows). Regexp#inspect produces a generally more readable
version of rxp.
So it seems a working solution, but it will store the exp with an unusual syntax and in order to get the string to store I need to build it manually with /my-exp/.to_s. Also I may not be able to edit to regexp directly. For instance a simple regexp produces:
/foo/i.to_s # => "(?i-mx:foo)"
The other option is to eval the field content so I might store the plain expression in the db column and then doing an eval(record.pattern) to get the actual regexp. This is working and since I'm the only one who will be responsible to manage the regexp records there should be no issues in doing that, except application bugs ;-)
Do I have other options? I'd prefer to not doing eval on db fields but on the other side I don't want to work with a syntax which I don't know.
use serialize to store your regex 'as-is'
class Foo < ActiveRecord::Base
serialize :my_regex, Regexp
end
see the API doc to learn more about this.
Not sure I understand your constraints exactly.
If you store a string in db, you could make a Regexp from it:
a = 'foo'
=> "foo"
/#{a}/
=> /foo/
Regexp.new('dog', Regexp::EXTENDED + Regexp::MULTILINE + Regexp::IGNORECASE)
=> /dog/mix
There are other constructors, see doc.
The very best solution to not use eval'd code is to store the regexp part in a string column and flags in a separate integer column. In this way the regexp can be built with:
record = Record.new pattern: 'foo', flags: Regexp::IGNORECASE
Regexp.new record.pattern, record.flags # => /foo/i
You can use #{} within regular expressions to insert variables, so you could insert a carefully cleaned regexp by storing "foo" in the db under record.pattern as a string, and then evaluating it with:
/#{record.pattern}/
So, in the db, you would store:
"pattern"
in your code, you could do:
if record.other_field =~ /#{record.pattern}/
# do something
end
This compiles the regexp from a dynamic string in the db that you can change, and allows you to use it in code. I wouldn't recommend it for security reasons though, see below:
Obviously this could be dangerous, as the regex can contain ruby code, so this is simpler, but in terms of danger, it is similar to eval:
a = "foo"
puts a
=> foo
b = "#{a = 'bar'}"
a =~ /#{b}/
puts a
=> bar
You might be better to consider whether for security it is worth decomposing your regex tests into something you can map to methods which you write in the code, so you could store keys in the db for constraints, something like:
'alpha,numeric' etc.
And then have hard-coded tests which you run depending on the keys stored. Perhaps look at rails validations for hints here, although those are stored in code, it's probably the best approach (generalise your requirements, and keep the code out of the db). Even if you don't think you need security now, you might want it later, or forget about this and grant access to someone malicious.