Rails 4 LIKE query - ActiveRecord adds quotes
Your placeholder is replaced by a string and you're not handling it right.
Replace
"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search
with
"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%"
Safe ActiveRecord like query
To ensure that your query string gets properly sanitized, use the array or the hash query syntax to describe your conditions:
Foo.where("bar LIKE ?", "%#{query}%")
or:
Foo.where("bar LIKE :query", query: "%#{query}%")
If it is possible that the query
might include the %
character and you do not want to allow it (this depends on your usecase) then you need to sanitize query
with sanitize_sql_like
first:
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
Rails ActiveRecord: How to use bind variables with double quotes on jsonb
You can't put parameter placeholders inside quoted strings.
The fact that Rails allows you to do that and substitutes a single-quoted string inside the single-quoted string indicates that Rails has failed (as usual) to understand rules of SQL.
But you can put a parameter placeholder in an expression, with other strings. I am not a regular PostgreSQL user, but I assume you can concatenate strings together to form a complete JSON literal:
Blog.where("upload_data @> '[ { \"name\": \"' || ? || '\"}]'", name)
You might find it makes your code more clear if you parameterize the whole JSON value. Use %Q()
to avoid needing to backslash the literal double-quotes.
Blog.where("upload_data @> ?", %Q([ { "name": "#{name}" } ]))
Or to make sure to generate valid JSON, I'd put the expression in Ruby syntax, and then convert to JSON:
Blog.where("upload_data @> ?", JSON.generate( [{name: name}] ))
Escaping Quotes in Rails Query
You don't need to interpolate to create the arguments for where
, just bind it/them:
Merchant.where("lower(name) = ?", mname)
Active Record will take care of that and your query will most likely look like this:
SELECT "merchants".* FROM "merchants" WHERE (lower(name) = 'brandy''s boy')
Escaping is doing in the internals of the framework, from the docs:
If an array is passed, then the first element of the array is treated
as a template, and the remaining elements are inserted into the
template to generate the condition. Active Record takes care of
building the query to avoid injection attacks, and will convert from
the ruby type to the database type where needed. Elements are inserted
into the string in the order in which they appear.
User.where(["name = ? and email = ?", "Joe", "joe@example.com"])
# SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com';
Doing:
Merchant.where(["lower(name) = ?", mname])
Is pretty much the same as doing:
Merchant.where("lower(name) = ?", mname)
So your query is handled as stated above.
Search using like query in Ruby on Rails
It's often true that a bad name indicates wrong thinking. I believe your name Search
for the model is in this category. It should probably be called Tutorial
, no? Search is something you do to a model, not the model itself.
If this guesswork is correct and the model is now called Tutorial
and it has a field called name
that is a string, then your model will be
class Tutorial < ActiveRecord::Base
def self.search(pattern)
if pattern.blank? # blank? covers both nil and empty string
all
else
where('name LIKE ?', "%#{pattern}%")
end
end
end
This makes the model "smart" on how to search through tutorial names: Tutorial.search('foo')
will now return all tutorial records that have foo
in their names.
So we can create a controller that uses this new functionality:
class SearchController < ApplicationController
def show
@tutorials = Tutorial.search(params[:q])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @tutorial }
end
end
end
The corresponding view must display the tutorials. Yours doesn't. The simplest way to do this is write a partial that renders exactly one tutorial. Say it's called _tutorial.html.erb
.
Then in the view for Search
, you need to add
<%= render :partial => @tutorials %>
to actually display the search results.
Addition
I'll build a little example.
# Make a new rails app called learning_system
rails new learning_system
# Make a new scaffold for a Tutorial model.
rails g scaffold Tutorial name:string description:text
# Now edit app/models/tutorial.rb to add the def above.
# Build tables for the model.
rake db:migrate
rails s # start the web server
# Now hit http://0.0.0.0:3000/tutorials with a browser to create some records.
<cntrl-C> to kill the web server
mkdir app/views/shared
gedit app/views/shared/_search_box.html.erb
# Edit this file to contain just the <%= form_tag you have above.
# Now add a header at the top of any view you like, e.g.
# at the top of app/views/tutorials/index.html.erb as below
# (or you could use the layout to put it on all pages):
<h1>Listing tutorials</h1>
<%= render :partial => 'shared/search_box' %>
# Make a controller and view template for searches
rails g controller search show
# Edit config/routes.rb to the route you want: get "search" => 'search#show'
# Verify routes:
rake routes
search GET /search/:id(.:format) search#show
tutorials GET /tutorials(.:format) tutorials#index
POST /tutorials(.:format) tutorials#create
new_tutorial GET /tutorials/new(.:format) tutorials#new
edit_tutorial GET /tutorials/:id/edit(.:format) tutorials#edit
tutorial GET /tutorials/:id(.:format) tutorials#show
PUT /tutorials/:id(.:format) tutorials#update
DELETE /tutorials/:id(.:format) tutorials#destroy
# Edit app/controllers/search_controller.rb as above.
# Create app/views/tutorial/_tutorial.html.erb with following content:
<tr>
<td><%= tutorial.name %></td>
<td><%= tutorial.description %></td>
</tr>
# Edit app/views/search/show.html.erb to have following content:
<h1>Show Search Results</h1>
<table>
<%= render :partial => @tutorials %>
</table>
Now try a little test. Fill in a search criterion and press the Search button.
How do I properly escape double quotes in a PostgreSQL like query?
The problem is that there is not a unique way to express that data in YAML:
hide_on_map:
- no
- yes
"hide_on_map": [false, true]
are both valid YAML representations of your data.
I fear you cannot avoid using some native type, or at least a "compacted" JSON text (which would contain literally '"hide_on_map":[false,true]'
.
Rails ActiveRecord includes where with like
Just use string as argument for where
scope :filter, -> (query) { joins(:city).where('cities.name LIKE ?', "%#{ query }%") }
ActiveRecord query only if attribute is inferior than another
You can just have a string of what would be your query inside the where, i usually use this approach because it makes me feel like im writing plain SQL.
This should work for you:
@meals = Meal.where("week_day = 1
AND vacation_mode = false
AND today_orders < max_daily_orders")
Related Topics
How to Delete Duplicate Records in MySQL Database
Foreign Key Constraint May Cause Cycles or Multiple Cascade Paths
How to Comma Delimit Multiple Rows into One Column
Count the Number of Occurrences of a String in a Varchar Field
Table Naming Dilemma: Singular Vs. Plural Names
How to Pass Parameters to Query
Difference Between Language SQL and Language Plpgsql in Postgresql Functions
How to Find Similar Results and Sort by Similarity
MySQL Query to Dynamically Convert Rows to Columns
Rails 4 Like Query - Activerecord Adds Quotes
Difference Between Lateral Join and a Subquery in Postgresql
Two SQL Left Joins Produce Incorrect Result
Is There a Combination of "Like" and "In" in Sql
Can You Use an Alias in the Where Clause in MySQL
How to Delete Using Inner Join With SQL Server
SQL Counting All Rows Instead of Counting Individual Rows
Maximum Size For a SQL Server Query? in Clause? Is There a Better Approach