Operator does not exist: character varying[] - ruby-on-rails

Running a simple statement on my User model but keep on getting errors about the operator not matching any of the given arguments. I've never run into anything like this before and don't know how to handle it. I understand I have to perhaps add type casts, but in my POSTGRES database the column keywords is of type array.
#users = User.where("keywords ILIKE ?", "%#{params[:keywords]}%")
How do you handle this?
Exact error message:
ActionView::Template::Error (PG::SyntaxError: ERROR: syntax error at or near "ANY"
LINE 1: SELECT "users".* FROM "users" WHERE (ANY(keywords) LIKE '%an...
^
: SELECT "users".* FROM "users" WHERE (ANY(keywords) LIKE '%angularjs%')):
Thanks!

If you want to search in a postgres array you use the any operator.
Note, this solution assumes params[:keywords] is just a single string like apples or something. It also matches on exact match, not substrings.
#users = User.where('? = ANY(keywords)', params[:keywords])
If you need to use the ILIKE operator you must to something like
#users = User.where("array_to_string(names, ',') ILIKE ?", "%#{params[:keywords]}%")
or if you want to be fancy with regex
#users = User.where("array_to_string(names, ',') ~* ?", params[:keywords])

Related

OR condition in query

Try makes the following query:
title = "%#{params[:title]}%"
group = params[:group]
#foods = Food.order('visits_count DESC').where("title ILIKE ? OR group ILIKE ?", title, group).decorate
and in return I get the following error:
ActionView::Template::Error (PG::SyntaxError: ERROR: syntax error at or near "group"
LINE 1: ..."foods".* FROM "foods" WHERE (title ILIKE '%%' OR group ILIK...
^
: SELECT "foods".* FROM "foods" WHERE (title ILIKE '%%' OR group ILIKE '') ORDER BY visits_count DESC):
Any ideas?
Try
"group"
with double-quotes.
Since this is PostgreSQL, you need to quote identifiers using double quotes when case sensitivity is an issue or you're using a keyword as an identifier:
...where('title ILIKE ? OR "group" ILIKE ?', title, group)...
You'd be better off not using a keyword as a column IMO so that you don't have to worry about this sort of thing. I'd go with he quoting for now and then rename the column as soon as possible but that's just me.
While I'm here, you might want to leave out those checks when they don't make sense. This part of your query:
title ILIKE '%%'
will always match when title is not null so you might want to use an explicit not null check or leave it out entirely when there is no title. Similarly for "group" ILIKE '' which only matches when "group" is empty.

ActiveRecord find all records including spesific foreign word (case insensitive)

I would like to write an ActiveRecord query to fetch all records which include specific foreign language words (case insensitive) in the description column of records table.
I think I can use mb_chars.downcase which converts international chars to lower case successfully.
> "ÖİÜŞĞ".mb_chars.downcase
=> "öiüşğ"
However, when I try to use mb_chars.downcase in ActiveRecord query I receive the following error:
def self.targetwords
target_keywords_array = ['%ağaç%','%üzüm%','%çocuk%']
Record.where('description.mb_chars.downcase ILIKE ANY ( array[?] )', target_keywords_array)
end
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "mb_chars"
I will appreciate if you can guide me how to solve this problem.
You're trying too hard, you should let the database do the work. PostgreSQL knows how to work with those characters in a case-insensitive fashion so you should just let ilike deal with it inside the database. For example:
psql> select 'ÖİÜŞĞ' ilike '%öiüşğ%';
?column?
----------
t
(1 row)
You could say simply this:
def self.targetwords
target_keywords_array = ['%ağaç%','%üzüm%','%çocuk%']
Record.where('description ILIKE ANY ( array[?] )', target_keywords_array)
end
or even:
def self.targetwords
Record.where('description ilike any(array[?])', %w[ağaç üzüm çocuk].map { |w| "%#{w}%" })
end
or:
def self.targetwords
words = %w[ağaç üzüm çocuk]
likeify = ->(w) { "%#{w}%" }
Record.where('description ilike any(array[?])', words.map(&likeify))
end
As far as why
Record.where('description.mb_chars.downcase ILIKE ANY ( array[?] )', ...)
doesn't work, the problem is that description.mb_chars.downcase is a bit of Ruby code but the string you pass to where is a piece of SQL. SQL doesn't know anything about Ruby methods or using . to call methods.

Getting syntax error when using raw SQL SELECT command

I am not sure why I am getting the syntax error, according to this question everything should be okay. I could not find a way to execute a window function (postgres query which returns multiple columns GROUPED BY an individual column) that is the reason why I used raw SQL.
I am still new to Postgres, but I gathered that it may have to do with sanitization, but I do not know how to go about that either. Any help will be greatly appreciated, here is my code:
module TasksTestQuery
def self.call
query = "SELECT user_id, username, date, SUM(user_id) AS total_work, SUM(duration) AS total_duration OVER (PARTITION BY user_id) FROM tasks"
ActiveRecord::Base.connection.find_by_sql(query)
end
end
The exact error I'm getting is:
ActiveRecord::StatementInvalid
PG::SyntaxError: ERROR: syntax error at or near "(" LINE 1: SELECT user_id, username, date, SUM(user_id) AS total_work, SUM(duration) AS total_duration OVER (PARTITION BY user_id) FROM tasks
It should be
SUM(duration) OVER (PARTITION BY user_id) AS total_duration

How to search array through ransack gem?

I'm using ransack gem for searching in rails application. I need to search an array of email_ids in User table.
Referring to this issue at ransacking, I followed the steps and added this to the initializers folder ransack.rb
Ransack.configure do |config|
{
contained_within_array: :contained_within,
contained_within_or_equals_array: :contained_within_or_equals,
contains_array: :contains,
contains_or_equals_array: :contains_or_equals,
overlap_array: :overlap
}.each do |rp, ap|
config.add_predicate rp, arel_predicate: ap, wants_array: true
end
end
In the rails console, if i do like this:
a = User.search(email_contains_array: ['priti#gmail.com'])
it produces the sql like this:
"SELECT \"users\".* FROM \"users\" WHERE \"users\".\"deleted_at\" IS NULL AND (\"users\".\"email\" >> '---\n- priti#gmail.com\n')"
and gives error like this:
User Load (1.8ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND ("users"."email" >> '---
- priti#gmail.com
')
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: operator does not exist: character varying >> unknown
LINE 1: ...RE "users"."deleted_at" IS NULL AND ("users"."email" >> '---
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
: SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND ("users"."email" >> '---
- priti#gmail.com
')
Expected is this query:
SELECT "users".* FROM "users" WHERE ("users"."roles" #> '{"3","4"}')
What is wrong am I doing?
I met the same problem as you do. I'm using Rails 5, and I need to search an array of roles in User table
It seems that you have already add postgres_ext gem in your gemfile, but it has some problems if you are using it in Rails 5 application.
So it is a choice for you to add a contain query in Arel Node by yourself instead of using postgres_ext gem
And if you are using other version of Rails, I think it works well too.
I have an User model, and an array attribute roles. What I want to do is to use ransack to search roles. It is the same condition like yours.
ransack can't search array.
But PostgresSQL can search array like this:
User.where("roles #> ?", '{admin}').to_sql)
it produce the sql query like this:
SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND (roles #> '{admin}')
So what I want to do is to add a similar contains query in Arel Nodes
You can do it this way:
# app/config/initializers/arel.rb
require 'arel/nodes/binary'
require 'arel/predications'
require 'arel/visitors/postgresql'
module Arel
class Nodes::ContainsArray < Arel::Nodes::Binary
def operator
:"#>"
end
end
class Visitors::PostgreSQL
private
def visit_Arel_Nodes_ContainsArray(o, collector)
infix_value o, collector, ' #> '
end
end
module Predications
def contains(other)
Nodes::ContainsArray.new self, Nodes.build_quoted(other, self)
end
end
end
Because you can custom ransack predicate,
so add contains Ransack predicate like this:
# app/config/initializers/ransack.rb
Ransack.configure do |config|
config.add_predicate 'contains',
arel_predicate: 'contains',
formatter: proc { |v| "{#{v}}" },
validator: proc { |v| v.present? },
type: :string
end
Done!
Now, you can search array:
User.ransack(roles_contains: 'admin')
The SQL query will be like this:
SELECT \"users\".* FROM \"users\" WHERE \"users\".\"deleted_at\" IS NULL AND (\"users\".\"roles\" #> '{[\"admin\"]}')
Yeah!
I achieved this using ransackable scopes.
Where Author has a column "affiliation" consisting of an array of strings.
scope :affiliation_includes, ->(str) {where("array_to_string(affiliation,',') ILIKE ?", "%#{str}%")}
def self.ransackable_scopes(auth_object=nil)
[:affiliation_includes]
end
then the following works
Author.ransack(affiliation_includes:'dresden')
The advantage of this over use of postgres '#>' is that it can match substrings within the array, because of the %'s in the where command (get rid of %'s for whole string match). It is also case-insensitive (use LIKE instead of ILIKE for case-sensitive.

What is the appropriate ActiveRecord "Where" syntax for SQL "in"?

I have the following piece of code that's broken:
//user_posts_id is an array of integer values
#comment_notifications = Comment.where(["author_id != ? and post_id in ?", current_user.id, user_posts_id])
This is part of the error:
PG::SyntaxError: ERROR: syntax error at or near "1" LINE 1: ...
"comments" WHERE (author_id != 8 and post_id in 1,4,8,9,2,... ^ :
SELECT "comments".* FROM "comments" WHERE (author_id != 8 and post_id
in 1,4,8,9,2,3)
It doesn't seem to work because of the second conditional for "posts_id" and "user_posts_id". Also the "!=" complicates things a little, I think. What would be the appropriate way to write this ActiveRecord query?
Appreciate any suggestions! Thanks.
The problem is that you are sending the list without parens.
#comment_notifications = Comment.where(["author_id != ? and post_id in (?)", , current_user.id, user_posts_id])
If you look at the error it's telling you that the problem is near the "1", which is the first item in your list.
You can do it in Rails other way also :
#comment_notifications = Comment.where
.not(author_id: current_user.id)
.where(post_id: user_posts_id)

Resources