I have an application where I want to migrate from MetaWhere to Squeel in preparation for an upgrade to Rails 3.1.
This has been mostly a simple process but I have one case that causes me a bit of problems. The problem is that I have both the field and the value specified as variables. In my MetaWhere queries I could simply create symbols out of the field names and then use that in the query but Squeel does not use symbols but instead relies on instance_eval and I cannot figure out how to create a similar query using that...
An illustration of the original query could be:
Article.where("#{field_name}".to_sym.matches => '%' + field_value + '%')
How do I create a similar query in Squeel?
I know I can specify that I want to use the legacy symbol functionality but I would rather fully convert to the new syntax.
This works:
Article.where{article.send(field_name) =~ '%' + field_value + '%'}
The lowercase 'article' being the table name.
Related
It used in this part of code:
some_list.where("'#{#new_params[:email]}' ~~* name").any?
I tried to use google search, but i found only description of ~ rxp and this same unclear for me (especially in example). I had no experience with Ruby earlier, sorry if question is stupid.
~~* doen't actually have anything to with Ruby. Its the Postgres specific ILIKE operator for pattern matching.
This code is also a textbook example of a SQL injection vulnerability. The user input should be parameterized.
some_list.where("? ~~* name", #new_params[:email]).any?
This code is also pretty bizarre in that it has a Yoda condition. Normally you would write it as:
some_list.where("name ~~* ?", #new_params[:email]).any?
That has nothing do do with ruby. You construct a sql query and pass it into the #where method therefor it is a PostgreSQL operator.
The operator ~~ is equivalent to LIKE, and ~~* corresponds to ILIKE. There are also !~~ and !~~* operators that represent NOT LIKE and NOT ILIKE, respectively. All of these operators are PostgreSQL-specific.
That's what you are passing into it:
"foo#bar.com ILIKE name"
Any string in a where clause will be put into the SQL query which is then handed off to the database. So the ~~* syntax is not ruby, but SQL. My guess would be, that you are using Postgres as a DB, because:
The operator ~~ is equivalent to LIKE, and ~~* corresponds to ILIKE. There are also !~~ and !~~* operators that represent NOT LIKE and NOT ILIKE, respectively. All of these operators are PostgreSQL-specific.
Taken from: https://www.postgresql.org/docs/current/functions-matching.html#FUNCTIONS-LIKE
I'm new to ROR and trying to implement search in PostgreSQL database using Active Record. I've found that to make search case insensitive I can use ILIKE operator instead of equals and LIKE but not sure what to do when I need to use IN operator.
I'm getting a field name and a collection of values which I need to check and case sensitive search works like that:
records = records.where(filter['fieldName'] => filter['value'])
where filter['value'] is an array.
Is there a way to update that line to make it case insensitive?
If no then I believe the only way is to loop through that array and split IN into many OR operations and use ILIKE for every single value in that array(however I'm not sure how to use OR with Active Record)?
Thanks!
records.where("lower(#{filter['fieldName']}) in (?)", filter['value'].map(&:downcase))
This is what worked for me:
records = records.where('"' + filter['fieldName'] + '"' +
" ILIKE ANY ( array[?] )", filter['value'].map {|value| "%#{value}%" })
Try this ......
records.where("lower(#{filter['fieldName']}) in ?", filter['value'].map(&:downcase))
Hope this will work for you.
I am having trouble searching a string by the first letters. For example, if I have "animal", "ant", and "abs" in my database, I would like a query of "an" to return "animal" and "ant" (case insensitive). I got this working just fine with sqlite3:
Thing.where("name LIKE ?", params[:query] + '%')
However, this does not work in PostgreSQL (database used in pushing to Heroku). What is the correct query using PostgreSQL?
In PostgreSQL, you have to use ILIKE instead of LIKE to do a case-insensitive pattern match.
Your query will be:
Thing.where("name LIKE '?%'", params[:query])
This makes the query case insensitive:
Thing.where("lower(name) LIKE '?%'", params[:query].to_s.downcase)
If your production uses Postgres, I recommend development does it also, to prevent a further error like this!
Ransack allows me to build conditions with an attribute, a predicate and a value. I haven't been able to find any documentation on how to compare one attribute to another however. For instance, how could I create a condition for:
WHERE column_a < column_b
I've been using Ransack for quite a while, but I don't see any possibility to do what you are looking for. What you want is a "case -> when" statement, which can be produced in Rails or as SQL with ActiveRecord.
Ransack gives you the ability to create a custom SQL command, by defining attribute, predicate and value, which then translates into WHERE Statement you already mentioned. I don't see any possibility to tell Ransack directly to filter for what you want. However:
What you could is create a scope like:
scope :column_b_gt_columnb_a, -> { where('column_b > column_a') }
And then you can build your search like this:
Object({ column_b_gt_columnb_a: true })
Probably not really what you were looking, but I think that's the best you gonna get...
And if you want to do it with Rails you would do to compare values or use said where statement I used above.
Records.each do |i|
case i.variable_a
when i.variable_b
# do something when it's the same
when i.variable_a > i.variable_b
# do something when it's greater
end
end
For an example of an SQL statement look here
How do I compare two columns for equality in SQL Server?
Hope this helps a bit!
Let's assume I have a model called "product." Let's assume that product has three fields. These fields are 'name' (type string), 'cost' (type integer), and 'is_visible' (type bool).
1) How can I do a search query using the Rails "find" method (if there is another method, that's fine) so that I can search for all products with a cost greater than 100 AND is_visible is true?
2) What if we wanted to change this to search to where name != '' OR cost == 0?
This isn't a problem to do an SQL, but I would like to think that Rails has a way to do AND/OR queries to the database without using SQL.
Thanks!
You would need to use the conditions option on the find method. The conditions option can be either a Hash, Array, or String. There are lots of options for conditions, so I recommend reading the API help for it.
For example if you want to (1):
Product.find(:all, :conditions => ['cost > ? and is_visible is true', 100])
Or (2)
Product.find(:all, :conditions => ["name != '' or cost =0])
If you want something like LINQ you can check alternative Ruby ORMs like DataMapper or Sequel that provide more complex filtering capabilities.
For example in Sequel 2 you can write:
items.filter((:cost > 100) & (:is_visible = 1))
You can also use the bitwise "|" operator to get OR condition.
In DataMapper this will look like:
Model.all(:cost.gt => 100, :is_visible.eq => 1)
However some people don't like the fact that those features are implemented by overloading the standard Symbol class.
This is exactly the problem SQL was designed to solve, so why not to use it? Just add an appropriate :condition and your problem is solved.