diff --git a/README.md b/README.md index 3385666..9611d59 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ smart people at [Hashrocket](http://hashrocket.com/). For a steady stream of TILs from a variety of rocketeers, checkout [til.hashrocket.com](https://til.hashrocket.com/). -_530 TILs and counting..._ +_531 TILs and counting..._ --- @@ -346,6 +346,7 @@ _530 TILs and counting..._ - [Creating Records of Has_One Associations](rails/creating-records-of-has-one-associations.md) - [Custom Validation Message](rails/custom-validation-message.md) - [Demodulize A Class Name](rails/demodulize-a-class-name.md) +- [Generating And Executing SQL](rails/generating-and-executing-sql.md) - [Hash Slicing](rails/hash-slicing.md) - [Ignore Poltergeist JavaScript Errors](rails/ignore-poltergeist-javascript-errors.md) - [List The Enqueued Jobs](rails/list-the-enqueued-jobs.md) diff --git a/rails/generating-and-executing-sql.md b/rails/generating-and-executing-sql.md new file mode 100644 index 0000000..64befe5 --- /dev/null +++ b/rails/generating-and-executing-sql.md @@ -0,0 +1,49 @@ +# Generating And Executing SQL + +Rails' ActiveRecord can easily support 90% of the querying we do against the +tables in our database. However, there is the occasional exceptional query +that is more easily written in SQL -- perhaps that query cannot even be +written with the ActiveRecord DSL. For these instances, we need a way to +generate and execute SQL safely. The +[`sanitize_sql_array`](http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_array) +method is invaluable for this. + +First, let's get a connection and some variables that we can use downstream +in our query. + +```ruby +> conn = ActiveRecord::Base.connection +=> # +> one, ten = 1, 10 +=> [1, 10] +``` + +Now, we are ready to safely generate our SQL query as a string. We have to +use `send` because it is not publicly available. Generally, this is frowned +upon, but in my opinion it is worth breaking the private interface to ensure +our SQL is sanitized. + +```ruby +> sql = ActiveRecord::Base.send(:sanitize_sql_array, ["select generate_series(?, ?);", one, ten]) +=> "select generate_series(1, 10);" +``` + +Lastly, we can execute the query with our connection and inspect the +results. + +```ruby +> result = conn.execute(sql) + (0.4ms) select generate_series(1, 10); +=> # +> result.to_a +=> [{"generate_series"=>1}, + {"generate_series"=>2}, + {"generate_series"=>3}, + {"generate_series"=>4}, + {"generate_series"=>5}, + {"generate_series"=>6}, + {"generate_series"=>7}, + {"generate_series"=>8}, + {"generate_series"=>9}, + {"generate_series"=>10}] +```