The parameter email_or_phone_number comes from a client side and I need this for an authentication. However, the model has email and phone number fields separately.
What is the right way to parse the email_or_phone_number attribute, so then I could use find_by to find a user?
find_by(email: email, phone_number: phone_number)
If it's number, then it should become phone_number, but if it's not, then that is supposed to be an email.
A simple readable solution for your question would be using an OR query
Mongoid
User.where(email: params[:email_or_phone_number])
.or(phone_number: params[:email_or_phone_number])
.first
UPDATE Active Record
User.where(email: params[:email_or_phone_number])
.or(User.where(phone_number: params[:email_or_phone_number]))
The other method could be using a Regex for identifying Email Format or Phone Number Format of the value in params[:email_or_phone_number] but I have not come across any which are full proof in case of identifying there formats.
You can split email or number with a regex.
x = {email_or_phone_number:"3333"}
x[:email_or_phone_number].match(/^\d+/)
if x is nil, then
x[:email_or_phone_number].match(/\A([\w+\-]\.?)+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
else: is not valid input! Save result and pass res to find_by
Assuming that the desired behavior is that searching for 123 matches both greg123#example.com (an email) and 123123123 (a phone number) then the correct query would be:
User.where('email ILIKE :q OR phone ILIKE :q',
q: "%#{params[:email_or_phone]}%")
I'm not sure what your database is but keep in mind that this query may perform poorly on larger datasets. If that's the case I recommend you take a look at pg_trgm (Postgres-only) or full-text search solutions.
Related
Hi im fetching the user input and displaying the records that matches the condition, my query will look like
customers = customers.where('customers.contact_num ilike :search', {search: "%#{options[:search_contact]}%"})
here in db the contact number is stored in string with the format (091)-234-5678 like that
on while searching the user on basis of contact number if i search like this
091 it filters the number correctly, but while searching like 0912, it doesn't display record due to the braces, so how to modify the query to neglect the ) and - while searching..
As im new to the domain please help me out
thanks in advance
What about using REGEXP_REPLACE to remove all non-digit chars from the search - something like below?
customers = customers.where("REGEXP_REPLACE(customers.contact_num,'[^[:digit:]]','','g') ilike :search", {search: "%#{options[:search_contact]}%"})
Changing the query is hard. Let's not do that.
Instead right a quick script to transforms your numbers into
1112223333 form. No formatting at all. Something like:
require 'set';
phone = "(234)-333-2323"
numbers = Set.new(["1","2","3","4","5","6","7","8","9","0"])
output = phone.chars().select{|n| numbers.include?(n)}.join("")
puts output
=> "2343332323"
Then write a little function to transform them into display form for use in the views.
This will make your query work as is.
So let's say i have a Customer model with array column phones.
It's pretty easy to find all customers with given phone
Customer.where('? = ANY(phones)', '+79851234567')
But i can't figure out how to use LIKE with wildcard when i want to find customers with phones similar to given one, something like:
Customer.where('ANY(phones) LIKE ?', '+7985%')
I'm using PostgreSQL 9.5 and Rais 4.2
Any ideas?
I think, first of all, its better to use second table phones with fields customer_id, phone_number. I think it's more rails way ). In this way you can use this query
Phone.where("phone_number LIKE ?", '%PART%').first.customer
If you serialize your array in some text field, by example JSON, you should use % on both sides of your pattern:
Customer.where('phones LIKE ?', '%+7985%')
If you have an array in your database, you should use unnest() function to expand an array to a set of rows.
Can you try this
Customer.where("array_to_string(phones, ', ') like ?", '+7985%')
I believe this will work.
I am using MySql2 in my Rails application. I am trying to make an activerecord query that returns all records that have specified fields containing a string. I have read that downcasing my input and then using lower(column_name) LIKE 'string' should do the trick, but this does not appear to work. My query is exactly as follows:
search = params[:search].to_s.downcase
#current_user.patients.where("lower(last_name) LIKE ? OR lower(first_name) LIKE ? OR lower(identifier) LIKE ?", "%#{search}%", "%#{search}%", "%#{search}%")
Let's say I have a record with the last name "Abbott". When my search param is "Abb" or "bot", this record is returned. However, when the search param is "abb" or "Bot", nothing is returned. It appears that the query is still case sensitive??
I have looked all over and cannot seem to find an answer. I have read multiple times that lower(column_name) should work, but it does not.
Any help is appreciated. Thanks!
I figured it out. It was indeed because the fields were stored as binary values (thanks Vincent). By casting the binary fields as a CHARs, I was able to case-insensitively compare them:
#current_user.patients.where("CAST(last_name AS CHAR) LIKE ? OR ...
So, in my rails app I developed a search filter where I am using sliders. For example, I want to show orders where the price is between min value and max value which comes from the slider in params. I have column in my db called "price" and params[:priceMin], params[:priceMax]. So I can't write something kinda MyModel.where(params).... You may say, that I should do something like MyModel.where('price >= ? AND price <= ?', params[:priceMin], params[:priceMax]) but there is a problem: the number of search criteria depends on user desire, so I don't know the size of params hash that passes to query. Are there any ways to solve this problem?
UPDATE
I've already done it this way
def query_senders
query = ""
if params.has_key?(:place_from)
query += query_and(query) + "place_from='#{params[:place_from]}'"
end
if params.has_key?(:expected_price_min) and params.has_key?(:expected_price_max)
query += query_and(query) + "price >= '#{params[:expected_price_min]}' AND price <= '#{params[:expected_price_max]}'"
end...
but according to ruby guides (http://guides.rubyonrails.org/active_record_querying.html) this approach is bad because of SQL injection danger.
You can get the size of params hash by doing params.count. By the way you described it, it still seems that you will know what parameters can be passed by the user. So just check whether they're present, and split the query accordingly.
Edited:
def query_string
return = {}
if params[:whatever].present?
return.merge({whatever: #{params[:whatever]}}"
elsif ...
end
The above would form a hash for all of the exact values you're searching for, avoiding SQL injection. Then for such filters as prices you can just check whether the values are in correct format (numbers only) and only perform if so.
Is there a way to set an attribute in mongoid for case insensitive searches?
Lets say that somebody has a username: IAmGreat and I want to find the users data using their unique username without butchering it and changing it to iamgreat.
Thanks
Actually you can search case insensitive. But you have to search with an regex!
Here is an example how I'm using it at http://zeit.io
User.where(email: /\A#{Regexp.escape(email)}\z/i).first
With the / you are starting and ending the regex. The i after the regex means case insensitive. \A Means the string has to start with the search string and \z means the string has to end with the search string. This is important if you are looking for an exact match.
You can even try something like:
User.where(username: /#{username}/i).first
if you are using rails or mongoid you can try the ff:
#user = User.where({:username => /.*#{name}.*/i })
Why not just down a User.login.downcase (or whatever your model/attribute combination is) when making the comparison? This will leave the capitalization in the DB as-is, but downcase the field just for comparison.
If your application doesn't need to store user-input as case-sensitive, just convert the input to uppercase or lowercase on the way in. Example,
username = params[:username].to_s.downcase
Otherwise, if performance is an issue for you (case-insensitive regex cannot take advantage for indexes) the right way to go about it is to store a backup field for username
field :username_downcase
And then do the query:
User.where(username_downcase: params[:username].to_s.downcase)