case insensitive search in rails - an example from Beginning Rails - ruby-on-rails

Could some on help me to turn the following search into case - insensitive?
Here is the piece of code for earching "title" field in event module:
# Add each field to the conditions array
searchable_fields.each_pair do |field, value|
conditions << "#{field} LIKE ?"
values << "%#{value}%"
end
Here is the data I have entered:
Concert
■Posted by: bancova
■2010-03-14
■boston
test
the "Concert" is the title of this event.
now, when I entered "concert" (small c), I cannot get the event.
however, when I entered "Concert", or "oncert", or "cert"...I can get it.
Could some some friend explain the code and teach me how to make it case insensive?
thanks.

I'm unfamiliar with the tutorial you're using but it looks like it's a database problem, not a Ruby/Rails problem. The problem is that your database is case sensitive so 'Concert' matches because that's what's in the DB, but 'concert' doesn't because it's not an actual match with 'Concert'.
Anyway, the actual solution will depend on your database and how it's configured but lets assume it's MySQL, then your solution would look like this
searchable_fields.each_pair do |field, value|
conditions << "#{field} LIKE LOWER(?)"
values << "%#{value.downcase}%"
end
value.downcase will change the input string to all lowercase and the LOWER sql function will do the same on the database side. They should now match. IF you're using SqlLite or Postgres you'll need to look up their lowercase functions but the rest will still be the same.

Related

Case insensitive with special special characters in Rails model

I have the cars_tables and in its name column I have names with special characters, for example:
car_names = Car.pluck :name
=> ["Cárrozería", "Óther Cars", "Forede Lúis", "Ságara Mbobe"]
The values ​​are automatically parameterized making the special characters disappear
car_name_parameterize << ["Cárrozería", "Óther Cars", "Forede Lúis", "Ságara Mbobe"].map { |name| name.parameterize }.join(', ')
=> ["carrozeria", "other-cars", "forede-luis", "sagara-mbobe"]
and with the parameterized values ​​I would like to do a query but I can't since the names have special characters that prevent me from doing so
first_car_name = car_name_parameterize.first
=> carrozeria
Car.find_by('name ILIKE ?', "%first_car_name%")
=> nil ;; nil because the word **carrozeria** doesn't have í special character,
Car.find_by_name "carrozería"
=> #<Car:0x300312318 id: 1, name: "carrozería"...> ;; If it does the query without returning nil but it is because I consulted its name manually when placing "carrozería"
In short, I am looking to make the queries with the columns with the same name but with special characters (usually these characters usually have accents) recognized.
I am looking to make queries to the name of the cars table, canceling the special characters, such as the accent between the words for example
I have also tried the gsub method without success.
If you could help me I would be very happy and thank you for taking the time to read me.
You will need to use the unaccent extension (docs: https://www.postgresql.org/docs/current/unaccent.html).
Basically, install the extension:
CREATE EXTENSION unaccent;
And then you will be able to use the unaccent() function:
where("unaccent(name) LIKE ?", "%#{your_value}%")
Read more details and different alternatives in the following entry: Postgres accent insensitive LIKE search in Rails 3.1 on Heroku
Thanks to the link that the user #markets shared with me, I used the unaccent method to avoid the settlements and then the lower case and it worked for me.
cart_name = "carrozería"
Car.find_by("lower(unaccent(name)) LIKE ?", "%#{cart_name}%")

Rails SQL Injection: How vulnerable is this code?

I'm trying to understand SQL Injection. It seems like people can get pretty creative. Which gets me wondering about my search-based rails webapp I'm making.
Suppose I just fed user-entered information directly into the "where" statement of my SQL query. How much damage could be done to my database by allowing this?
def self.search(search)
if search
includes(:hobbies, :addresses).where(search)
else
self.all
end
So basically, whatever the user types into the search bar on the home page gets fed straight into that 'where' statement.
An example of a valid 'search' would be:
"hobby LIKE ? OR (gender LIKE ? AND hobby LIKE ?)", "golf", "male", "polo"
Does the fact that it's limited to the context of a 'where' statement provide any sort of defense? Could they still somehow perform delete or create operations?
EDIT:
When I look at this tutorial, I don't see a straightforward way to perform a deletion or creation action out of the where clause. If my database contains no information that I'm not willing to display from a valid search result, and there's no such thing as user accounts or admin privileges, what's really the danger here?
I took this from another post here: Best way to go about sanitizing user input in rails
TL;DR
Regarding user input and queries: Make sure to always use the active record query methods (such as .where), and avoid passing parameters using string interpolation; pass them as hash parameter values, or as parameterized statements.
Regarding rendering potentially unsafe user-generated html / javascript content: As of Rails 3, html/javascript text is automatically properly escaped so that it appears as plain text on the page, rather than interpreted as html/javascript, so you don't need to explicitly sanitize (or use <%= h(potentially_unsafe_user_generated_content)%>
If I understand you correctly, you don't need to worry about sanitizing data in this manner, as long as you use the active record query methods correctly. For example:
Lets say our parameter map looks like this, as a result of a malicious user inputting the following string into the user_name field:
:user_name => "(select user_name from users limit 1)"
The bad way (don't do this):
Users.where("user_name = #{params[:id}") # string interpolation is bad here
The resulting query would look like:
SELECT users.* FROM users WHERE (user_name = (select user_name from users limit 1))
Direct string interpolation in this manner will place the literal contents of the parameter value with key :user_name into the query without sanitization. As you probably know, the malicious user's input is treated as plain 'ol SQL, and the danger is pretty clear.
The good way (Do this):
Users.where(id: params[:id]) # hash parameters
OR
Users.where("id = ?", params[:id]) # parameterized statement
The resulting query would look like:
SELECT users.* FROM users WHERE user_name = '(select user_name from users limit 1)'
So as you can see, Rails in fact sanitizes it for you, so long as you pass the parameter in as a hash, or method parameter (depending on which query method you're using).
The case for sanitization of data on creating new model records doesn't really apply, as the new or create methods are expecting a hash of values. Even if you attempt to inject unsafe SQL code into the hash, the values of the hash are treated as plain strings, for example:
User.create(:user_name=>"bobby tables); drop table users;")
Results in the query:
INSERT INTO users (user_name) VALUES ('bobby tables); drop table users;')
So, same situation as above.
I hope that helps. Let me know if I've missed or misunderstood anything.
Edit Regarding escaping html and javascript, the short version is that ERB "escapes" your string content for you so that it is treated as plain text. You can have it treated like html if you really want, by doing your_string_content.html_safe.
However, simply doing something like <%= your_string_content %> is perfectly safe. The content is treated as a string on the page. In fact, if you examine the DOM using Chrome Developer Tools or Firebug, you should in fact see quotes around that string.

How to search for wild card in Rails

Im trying to search my User model for all Users that start with any integer, I have code for individual letters and it works, but Im having trouble getting it working with a wild card. Right now I have this code:
in my view:
<%= link_to '#', users_charlist_path(:char => '[0123456789]' %>
and in my controller I have:
def charlist
#a = User.where('goal like ?', "#{params[:char]}%").to_a
end
how ever, '[0123456789]', doesnt seem to work as it does not return anythign to me even though I have users whose names begin with an integer. how do i do this?
The where method is a part of ActiveRecord which maps the objects to the database. So how you can query the database with a regex depends on which db you are using not on ruby. You need to look up the regex functions of the database your using. For mysql you can find them here:
http://dev.mysql.com/doc/refman/5.1/de/regexp.html
An alternative is to select all objects an use the select method to filter the results that match your needs. That method is documented here:
http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-select
On big amounts of data I whould suggest to use the database even if that means your application isnt 100% portable between different database systems.

Complex search screens in Rails 3

I need to implement some search functionality within a Rails application. Most of the stuff I have found is generally aimed at simple plain-text search. I am trying to implement something much more specific. The sort of functionality I am looking to create is this (from a C application):
http://andyc.ac/query.gif
The form just submits the data entered by the user. So I need to translate strings like "3..7" into SQL conditions for the where method e.g.
TestLine.where( "test_int >= ? and test_int <= ?", MinInt, MaxInt )
It seems like this is something that already exists somewhere. The exact format expected is not too important, as the users are not shared between the Rails and C applications. How would this be done?
FWIW the specific functionality you describe is actually supported directly. Well.. almost. From the docs:
A range may be used in the hash to use the SQL BETWEEN operator:
Student.where(:grade => 9..12)
Of course then it's a matter of translating the user's string input to a Range, which isn't very complex, e.g.:
def str_to_range str
str =~ /(\d+)\.\.(\d+)/
Range.new *$~.captures.map(&:to_i)
end
It would probably make the most sense in a scope on your model. (Of course a shortcut would be to simply eval '9..12' but evaling input from the end user is a really, really bad idea.)
Give a look at thinking sphinx(http://freelancing-god.github.com/ts/en/). It might make your task a lot easier. You can search in that:
http://freelancing-god.github.com/ts/en/searching.html#basic

Is this Rails 3 search vulnerable to SQL injection?

Suppose I've got a search box on a page in a Rails 3 app where you can search for a client by business name or city. In my controller's index method I do this:
if params[:search]
#clients = Client.where("clients.business_name LIKE :business_name OR clients.city = :city", :business_name => "%#{params[:search]}%", :city => params[:search])
Those hash values get substituted into the SQL and surrounded in quotes. If my input into the search box includes quotes or other dangerous characters, I'll see them being escaped in the development log, like:
...WHERE (clients.business_name LIKE '%Something\' DROP TABLE Foo%'...
Or
...WHERE... OR clients.city = 'Something OR 1=1')
So, since the OR 1=1 is inside the quotes Rails adds, it just produces no match for the city name, and since the quote in the DROP TABLE attempt is escaped, it also produces no match for the business name.
This isn't using actual prepared statements, where the query is sent to the database first without the search values filled in, then subsequently, the search values are sent to the database to fill in. I thought that was the safest approach, but Rails doesn't do it; I think this is because it's not available in all databases and implementations vary.
Is this open to SQL injection in some way? I don't see it, but again, it's not using prepared statements, so I wonder. If there's a vulnerability, how could I do this more safely?
No, there's not a SQL injection vulnerability here. ActiveRecord will call connection.quote on the values of the hash that you passed in as the second parameter to where, so you are safe.
The only potential SQL injection point I could think of would be if there were some undiscovered bug in connection.quote, which is pretty unlikely.

Resources