Order by last name - ruby-on-rails

I am trying to set the default scope for my User model. Each user has one name column. The problem is that I would like to order users by the first letter of their last name. This would be the start of the last word from the name. For example, a users name may be "Kevin John Smith", I would like to order by Smith. I currently have default_scope order('name ASC'), but this sorts by the first letter of the first name. How would I convert this to sort by the first letter of the last name? Thanks!

Try this:
User.select("users.*, SUBSTRING_INDEX(users.name, ' ', -1) AS lastname").limit(10).order('lastname ASC')
SUBSTRING_INDEX is one of the mySQL string functions.
For PostgreSQL split_part should work:
User.select("users.*, split_part(users.name, ' ', 3) AS lastname").limit(10).order('lastname ASC')
I am not sure, though try with -1 too:
User.select("users.*, split_part(users.name, ' ', -1) AS lastname").limit(10).order('lastname ASC')
Because, the latter one will ensure that the last string after split is used which will cover the cases where user has just first name and last name.
Make sure you use unscoped, which returns a scope for this class without taking into account the default_scope.

Related

Searching for specific characters in user input

Within my house table I have a postcode for each house.
I also have an index view for my housing table that contains a table which contains headings such as 'Name', 'Address', 'State'. I was looking to integrate a text_field_tag that would allow user's to input the 9 digits of a postcode in order to filter the table to only show the house with that postcode. However, I also want the user to be able to input the first 4 digits of their postcode e.g. '7644' and it would display all houses that begin with '7644' e.g. two records one with the postcode of the '76444-5645' and '76443-123'. Ideally I would apply logic through my '#search' variable within my houses controller. However I am up to any ideas or tips.
In order to instantiate the house model I would use #house = House.all
I'll be honest I don't know where to begin with this. I have arel_sql in my system so I assume that would be used to query for the search.
It depends on how your models/controllers are defined but you're probably looking for the SQL operator LIKE + '%', which allows you to search for a pattern in a given column. Example:
LIKE Operator
Description
WHERE CustomerName LIKE 'a%'
Finds any values that start with "a"
Assuming you're using ActiveRecord and your model is House, it wouldn't event need to instantiate all houses. Your code would look something like this:
postcode = '7644'
#houses = House.where('postcode LIKE ?', "#{postcode}%") # this returns where the postcode starts with '7644'
another similar SO answer for reference

Rails query to substitute field and query

could someone please help me to write a query to substitute hyphens in rails DB field with space?
For eg:
If I have a field called 'name' in a table User having a value 'asdc-sd bc', and want to remove special characters like '-' and replace it with space to match with a given name 'asdc sd bc'.
I tried using lower to convert the name to lowercase but am not able to find out how to substitute the hyphens with space. Please help!
You can use SQL REPLACE function to replace - with spaces(' ').
For example, if you are querying on name column of User model, you can write your query like below:
query_str = 'asdc sd bc'
User.where("REPLACE(name, '-', ' ') = ?", query_str)

How to capture regex first occurence and interpolate into string with postgreSQL

I'm trying to concatenate the digits from a string that starts with 'CityName' into a separate string. I have the concatenation part. My issue is being able to access the matches from the regex
I have a regex in rails that looks like /CityName\s*(\d+)/i. I'm super new to regex and it's hard for me to wrap my head around the docs. But I'm assuming that this regex will find any digits after the CityName case intensively. And then it's interpolated if it matches an attribute on my model.
regex = /CityName\s*(\d+)/i
if line_1 =~ regex
"C#{$1}"
...
end
But further along in the execution, it's slowing down because I have to iterate over a lot of records. I have a query in psql that will do that calculations that I need, however I'm having a hard time implementing this regex replacement. My attempts so far look like:
CASE
when addr.line_1 ~* 'CityName\s*(\d+)' then 'C' || regex_matches('CityName\s*(\d+)')[0]
...
I'm having a hard time finding a solution to grab the first occurrence of the regex match. Thanks for any tips :D
EDIT: I am trying to grab the digits after 'CityName' from a string if that string contains 'CityName'
Ultimately I need assistance with the regex and how to contactenate the digits with 'C'
Your question is a bit unclear. Are you trying to add the digits to your selection or to filter records based on them?
If you just want to select them:
Address.select(%q{(regexp_matches(addr.line_1, 'CityName\s*(\d+)'))[1] as digits})
.map(&:digits)
If you want to filter based on then:
Address.where(%q{addr.line_1 ~ 'CityName\s*(\d+)'}).map &:email
.map(&:line_1)
Also a few notes:
Selecting digits case intensively does not really make sense. Digits
does not have case.
PostgreSQL arrays start from 1 instead of 0.
It seems you need a subquery or a WITH query:
SELECT tbl1.col1, sum(...), min(...) FROM (SELECT ..., CASE ...yourregex stuff... END col1 FROM ...) tbl1 GROUP BY 1;
WITH tbl1 AS (SELECT ..., CASE ...yourregex stuff... END col1 FROM ...) SELECT t.col1, sum(...) FROM tbl1 t GROUP BY 1;
If you need them regulary, you can also create views from the query or create a temp table, then you can use it in queries later.
Got it! Was able to finally start to figure out the regex.
WHEN addr.line_1 ~* '(?i)CityName\s*(\d+)' THEN 'C' || (SELECT (regexp_matches(addr.line_1, '(?i)CityName\s*(\d+)'))[1])
The (?i) allowed for case insensitive matching for CityName and then the concatenation worked. Thank you #ti6on for pointing out the index difference with postgres :D

Ruby On Rails Dynamic Where Search

I am using postgres for the db.
Service Address Controller contains this line
#service_addresses = ServiceAddress.where("customer_id =?" , params[:customer_id]).search(params[:search])
Service Address Model Method:
def self.search(query)
where("street LIKE ? OR city LIKE ?", "%#{query.to_s}%","%{query.to_s}%")
end
In my view I have a search bar that sends params
service_addresses?utf8=✓&search=123+Echo+Dr+New+York
Lets assume I have two columns on my view Street & City
If I search 123 Echo Dr. New York it will NOT return a record where Street = 123 Echo Dr. and the City = New York
However, if I simply search 123 Echo Dr. or 123 it will return all records that have that in the Street or City column. Similairly if I search New York it will return records that contain New York
I tried parsing out the search param into an array (successfully) and then using a loop to essentially build a string of "%#{parsed_query[i]}%" However when I tried to pass the string of binds to my where statement, but I got an error stating I have the wrong number of binds. It was treating my string variable as one bind.
Not able to use Data Tables gem!
Thank you SOF community.
Iterate over the tokens parsed from the query string to build up your query with ActiveRecord. Note that this will result in a SQL query many AND conditions.
#service_addresses = ServiceAddress.where("customer_id =?" , params[:customer_id])
parsed_query.each do |token|
#service_addresses = #service_addresses.search(token)
end
Update for case-insensitivity
To ignore case you can convert all strings to either uppercase or lowercase.
# Service Address Model Method:
def self.search(query)
where("upper(street) LIKE ? OR upper(city) LIKE ?", "%#{query.to_s.upcase}%","%{query.to_s.upcase}%")
end
Alternative
You may wish to look into document matching (full-text search). Postgres has some nice support for this. The topic is too much to cover here, but there are many resources online. A good place to start is the Postgres documentation
If I understand you problem, try this:
def self.search(keyword)
keyword_search = "%#{keyword.downcase}%"
where('lower(city) LIKE :search OR lower(street) LIKE :search', search: keyword_search)
end

CONCAT_WS for Rails?

No matter what language I'm using I always need to display a list of strings separated by some delimiter.
Let's say, I have a collection of products and need to display its names separated by ', '.
So I have a collection of Products, where each one has a 'name' attribute. I'm looking for some Rails method/helper (if it doesn't exist, maybe you can give me ideas to build it in a rails way) that will receive a collection, an attribute/method that will be called on each collection item and a string for the separator.
But I want something that does not include the separator at the end, because I will end with "Notebook, Computer, Keyboard, Mouse, " that 2 last characters should not be there.
Ex:
concat_ws(#products, :title, ", ")
#displays: Notebook, Computer, Keyboard, Mouse
Supposing #products has 4 products with that names of course.
Thanks!
you should try the helper to_sentence.
If you have an array, you can do something like
array.to_sentence. If your array has the data banana, apple, chocolate it will become:
banana, apple and chocolate.
So now if you have your AR Model with a field named, you could do something like
MyModel.all.map { |r| r.name }.to_sentence
#products.map(&:title).join(', ')
As #VP mentioned, Array#to_sentence does this job well in rails. The code for it is here:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/array/conversions.rb
Saying that, its use of the Oxford Comma is questionable :-)

Resources