1

I want to use constant of an array in SQL heredoc like:

ROLES = ['admin', 'staff', 'guest']

query = <<-SQL
  SELECT * FROM users
  WHERE role IN (#{ROLES})
SQL

ActiveRecord::Base.connection.execute(query)

but getting syntax error

ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR:  syntax error at or near "["
LINE 2: WHERE role IN (["admin", "staff", "guest"])
                       ^
2
  • Any reason why you're using ActiveRecord::Base.connection.execute for such a query? Commented Mar 30, 2020 at 11:54
  • @SebastianPalma here I am using ActiveRecord::Base.connection.execute(query) just to demonstrate the situation. Commented Mar 30, 2020 at 12:04

2 Answers 2

2

Instead of building your own Ruby to SQL converter you could also make use of the arel gem which already does the necessary escaping and quoting.

users = User.arel_table
ApplicationRecord.connection.execute(<<~SQL.squish)
  SELECT *
  FROM users
  WHERE #{users[:role].in(ROLES).to_sql}
SQL

Or if you'd like to go full arel.

ApplicationRecord.connection.execute(
  users.project(users[Arel.star])
       .where(users[:role].in(ROLES))
       .to_sql
)
Sign up to request clarification or add additional context in comments.

2 Comments

Or, if you need/want to go with straight SQL, use connection.quote to properly quote the strings.
@muistooshort I didn't know about that helper. Seems pretty handy, but might be better suited for Marek Lipka's answer, since that answer maps over the ROLES and quotes them.
0

Instead of passing the result of ROLES.inspect, you should make the string with roles yourself, I would use map and join for that purpose:

query = <<-SQL
  SELECT * FROM users
  WHERE role IN (#{ROLES.map { |role| "'#{role}'" }.join(',')})
SQL
ApplicationRecord.connection.execute(query)

3 Comments

ROLES.join(',') will reproduce like WHERE role IN ('admin, staff, guest') but it must be like WHERE role IN ('admin', 'staff', 'guest')
Right, how about now?
Note that this can still fail if the any of the ROLES include a ' character, and is susceptible to SQL injection if the dynamic data comes from an external user. Both shouldn't be an issue when looking at the question. But since OP says "here I am using ... just to demonstrate the situation" I thought it's worth mentioning.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.