简体   繁体   中英

What is the most elegant way in Ruby to substitute '?' in string with values in array

I have the following variables:

query = "(first_name = ?) AND (country = ?)" # string
values = ['Bob', 'USA'] # array

I need the following result:

result = "(first_name = Bob) AND (country = USA)" # string

The number of substitutions varies (1..20).

What is the best way to do it in Ruby?

If you don't mind destroying the array:

query.gsub('?') { values.shift }

Otherwise just copy the array and then do the replacements.

Edited: Used gsub('?') instead of a regex.

If you can control the query string, the String#% operator is what you need:

query = "(first_name = %s) AND (country = %s)" # string
values = ['Bob', 'USA'] # array
result = query % values
#=> "(first_name = Bob) AND (country = USA)"

You have to replace ? with %s in your query string.

query = "(first_name = ?) AND (country = ?)"
values = ['Bob', 'USA']
result = query.dup
values.each{|s| result.sub!("?",s) }
p query
# >> "(first_name = Bob) AND (country = USA)"
values.inject(query){|s1, s2| s1.sub("?", s2)}

Since this question is tagged , you could (should) use ActiveRecord::QueryMethods#where with Array Conditions .

This will raise ActiveRecord::PreparedStatementInvalid if you provide the wrong number of bind variables in values , which saves you from checking this yourself.

Not only is this elegant because Rails performs the substitutions for you, it will also help guard you against SQL injection attacks by sanitising your SQL in the process.

Example

Assuming your model is called User and query and value are as in your question, this:

User.where(query, *values)

...would generate SQL like:

SELECT * FROM users WHERE first_name = 'Bob' AND country = 'USA';

Display only

The example above will execute the query. To display the generated SQL without execution, simply invoke ActiveRecord::Relation#to_sql :

User.where(query, *values).to_sql

If you're using Rails (or at least ActiveRecord), I'd recommend using

ActiveRecord::Base.sanitize_sql_for_conditions(['(first_name = ?) AND (country = ?)', 'Bob', 'USA'])

Unless it's just for a regular where condition, in which case it will ActiveRecord will just do this for you in User.where('(first_name =?) AND (country =?)', 'Bob', 'USA')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM