If you’re working with SQL queries or other multi-line strings in Ruby, you might prefer using heredoc syntax (<<-SQL
) for its readability and syntax highlighting benefits. However, concatenating heredoc strings can sometimes lead to unexpected results due to hidden newline characters. Let’s explore how to merge heredoc strings seamlessly while preserving (or removing) newlines to build the final string you need.
Understanding Heredoc Behavior in Ruby
Heredoc syntax in Ruby captures all text between the opening <<-SQL
and the closing SQL
delimiter, including newline characters. For example:
base_sql = <<-SQL select * from table SQL condition = <<-SQL where table.column = true SQL
Here, base_sql
becomes " select * from table\n"
(with a trailing newline \n
), and condition
becomes " where table.column = true\n"
. When you concatenate them:
full_query = base_sql + condition
The result is:
" select * from table\n where table.column = true\n"
While this looks correct in Ruby, you might notice extra spaces or newlines when executing the SQL. Let’s break down how to control these characters.
Use String Concatenation as-Is
If your SQL engine tolerates newlines and indentation, simply using +
to concatenate works:
full_query = base_sql + condition
This produces:
select * from table where table.column = true
Pros:
- Simple and straightforward.
- Heredoc syntax retains editor highlighting.
Cons:
- Adds leading spaces (from heredoc indentation).
- Includes trailing newlines (may or may not matter for your use case).
Strip Unwanted Spaces and Newlines
If you want to remove leading spaces (from heredoc indentation) or trailing newlines, use .chomp
or the squiggly heredoc (<<~
):
Remove Trailing Newlines with .chomp
base_sql = <<-SQL.chomp select * from table SQL condition = <<-SQL.chomp where table.column = true SQL full_query = "#{base_sql} #{condition}" # => "select * from table where table.column = true"
Use Squiggly Heredoc to Remove Leading Spaces
Ruby’s <<~
syntax strips leading whitespace, which is helpful for indentation:
base_sql = <<~SQL.chomp select * from table SQL # => "select * from table" condition = <<~SQL.chomp where table.column = true SQL # => "where table.column = true" full_query = "#{base_sql} #{condition}"
Result:
select * from table where table.column = true
Interpolate Heredocs Directly
You can combine heredocs into a single string using interpolation:
full_query = <<~SQL #{base_sql.strip} #{condition.strip} SQL
This approach gives you full control over formatting and newlines.
Why Does the Original Example “Work” but Look Odd?
In your original code:
base_sql + condition
The output is technically correct, but Ruby’s #inspect
method displays strings with \n
and +
to indicate concatenation. When printed or used in a query, the newlines behave as expected:
puts base_sql + condition # Output: # select * from table # where table.column = true
The confusion arises from how Ruby represents strings internally, not the actual output.
Final Thoughts
Concatenating heredoc strings in Ruby is straightforward once you understand how newlines and indentation work. Use:
+
for simple concatenation..chomp
or<<~
to trim newlines and spaces.- String interpolation for dynamic formatting.
Heredocs are excellent for maintaining readability and editor features like syntax highlighting. Just remember to test the final string output to ensure it meets your requirements (especially for systems like SQL that may not care about whitespace but humans do!).