Case insensitive and inclusive ActiveRecord queries? - ruby-on-rails

I have views that print out a table of guides that have the word 'farming' in their titles.
def farming
t = Guide.arel_table
#guides = Guide.where(t[:title].matches('%farming'))
end
The problem is I want to show all guides that have at least any kind of spelling of the word 'farming' in it. So "Farming for Dummies" should show up in the search, too.
How do I do this?

In order to match Farming for Dummies you need to use farming%, i.e. % should be after the word farming.
Try the following to return all records with title including the word farming anywhere in title:
def farming
t = Guide.arel_table
#guides = Guide.where(t[:title].matches('%farming%'))
end

Related

How to make search box case-insensitive in rails?

I have simple search form in Rails, but when I using the search box, I need to enter the name exactly.
For instance, when I try to search for "more" it doesn't return anything, but when I do with "More", then it returns the records, So it seems like it behaves in a case-sensitive way.
Is it possible to make this case-sensitive way?
Here is my code
def self.search(search)
if search
star = Star.find_by(who: search)
if star
self.where(star_id: star)
else
Post.all
end
else
Post.all
end
end
You could do something like:
star = Star.where("UPPER(who) = ?", search.upcase).take
or
star = Star.where("LOWER(who) = ?", search.downcase).take
Either way, this coerces both your search term as well as the who value in the database before comparing them, which should get you the results that you need

Multiple word search in one field

I have search functionality with this code in the 'search.rb' file:
votsphonebooks = votsphonebooks.where("address like ?", "%#{address}%") if address.present?
There are multiple fields, this is just one of them.
How can I successfully change this line into something like a map to include multiple words.
Eg. If they type in '123 Fake St' - it will look for exactly that, but I want it to search for '123', 'Fake', 'St'.
First thing you should do is split the address by spaces:
addresses = params[:address].split(" ")
Then what you need is a OR query, you could do it by using ARel.
t = VotsPhoneBook.arel_table # The class name is my guess
arel_query = addresses.reduce(nil) do |q, address|
q.nil? ? t[:address].matches("%#{address}%") : q.or(t[:address].matches("%#{address}%"))
end
results = Post.where(arel_query)
Try using REGEXP instead of LIKE:
address_arr = address.split(" ")
votsphonebooks = votsphonebooks.where('address REGEXP ?',address_arr.join('|')) unless address_arr.blank?

.where.not with empty array

I have a problem trying to work with a NOT IN query (using Rails 4/Postgres, for reference) in an elegant way. I'm trying to get a list of all objects of a certain model that don't show up in a join table for a certain instance. It works , when you try a NOT IN query with an empty array, it throws an error because you can't look for NOT IN NULL.
The below code now works, but is there a better way than to use an unintuitive conditional to make a pseudo-null object?
def characters_selected
self.characters_tagged.pluck(:name)
end
def remaining_characters
characters = self.characters_selected
characters = ["SQL breaks if this is null"] if characters.empty?
# this query breaks on characters_selected == [] without the above line
Character.where("name NOT IN (?)", characters )
end
This is the ActiveRecord way:
def remaining_characters
characters = self.characters_selected
Character.where.not(:name => characters)
end
When characters.empty? the where clause becomes "WHERE (1=1)".

Rails: trying to store particular column value in an array

I am building an application in rails, and I have an items_controller which contains the methods application for create, show, edit, destroy etc.
However, I am trying to create my own method to access all the values in a specific column of my database and I am having greatly difficulty in capturing this data in an array.
I have tried the following ways of capturing the data (where 'quantity' is the column in the database for which I looking for):
#items = Item.find(params[:id])
#items2 = #item.find(params[:quantity])
I have also tried:
#items = Item.find(params[:quantity])
& even:
#items = Item.all
#items2 = #item.find(params[:quantity])
However, none of these methods appear to be working. For what I am doing it is not even essential to
know which quantity column values relate to which row...just getting a list of the column values would suffice.
If any one knows what is wrong here, the help you be very greatly appreciated!
Thanks.
UPDATE:
For clarity I am trying to retrieve all the data for a particular column in my database associated with the items_controller and filter the data for a particular piece of data (in this case the string "7" - as the data is returned from the db as a string when using the Items.all method.
I then want a counter to increase each time the "7" is encountered in the quantity column.
def chartItems
#items = Item.find(params[:id])
#items2 = #items.find(params[:quantity])
#filter = custom_filter_for(#items2)
def custom_filter_for(value)
j=0 # counter initialised at 0
value.each do |x|
if x == "7" # checking for data equal to "7" - the num is retrieved as a string
j = j+1 # increase j counter by 1 whenever "7" is encountered as a quantity
end
return j
end
end
Your find parameter is handled as an id in this case:
#items = Item.find(params[:quantity])
All items are returned which has the id of your quantity parameter. This is clearly not what you want.
You can select Items based on quantity:
#items = Item.find_by_quantity(params[:quantity])
But if you need only the quantities in an array, this is what you are looking for:
#quantities = Items.select(:quantity).map(&:quantity)
Your updated question:
result = Items.find_by_quantity(params[:quantity]).count
In new versions of ActiveRecord, they've added the pluck which does essentially what #Matzi's select and map method does.
To get all item quantities, you could do
#quantities = Item.pluck(:quantity)
Also, I would double check your use of the find_by helpers. I think that find_by_quantity will only give you a single match back (#item, not #items). To get all, I think you really want to use where
#quantities = Item.where(:quantity => params[:quantity])
If you were to use the pluck I mentioned above, I think your filtering step could also be written pretty concisely. That filter is simply counting the number of 7's in the list, right?
#quantities = Item.pluck(:quantity)
#filtered_values = #quantities.select{|q| q == 7}.length
I hope this helps out.

Rails loop through 'A..Z' and beyond?

I need to generate a unique name based on a start_date of a model. I have the following code that's working. However, as you can see, it only supports up to letter Z. Is there a way that I can make it work for beyond Z, like this sequence? A,B,C,...X,Y,Z,AA,AB,AC,AD,AE...AZ,BA,BB,BC...
def generate_name
("A".."Z").each do |letter|
random_token = start_date.strftime("%m%d%y") + letter
break random_token unless Tour.where(name: random_token).exists?
end
end
def letters
('a'..'z').each { |i| yield i }
letters do |i|
('a'..'z').each { |j| yield i+j }
end
end
def generate_name
letters do |letter|
random_token = start_date.strftime("%m%d%y") + letter
break random_token unless Tour.where(name: random_token).exists?
end
end
Sam's answer looks like exactly what you requested but here's another possibly useful way to look at your problem:
Think of your string as a number in base 26, where the digits are represented by 'a'..'z'. The only difference between doing it this way and the way you requested is that the first two-digit number (err, two-letter string) will be ba rather than aa (assuming that you started counting with a = 0, b = 1, etc.) and you won't generate any strings starting with a (other than the first one) for the same reason you don't write whole numbers starting with 0 (other than the first one).
If it's useful for you to calculate very quickly that the name dw was the 100th one you generated, then this approach has merit. It's also a good way to work the word hexavigesimal into conversations or at least into documentation.
Thanks Sunxperous.
This worked:
def generate_name
("A".."ZZZ").each do |letter|
random_token = start_date.strftime("%m%d%y") + letter
break random_token unless Tour.where(name: random_token).exists?
end
end
You are looking for Kleene star. Not tested, but seems that RLTK gem can give you such functionality.

Resources