Ruby
Rails

String#squish で長い SQL 文字列を 1 行にする

問題

次のように where メソッドの引数に SQL 文字列を渡しているコードがあるとします。

[1] pry(main)> Character.where('EXISTS (SELECT 1 FROM anime_characters WHERE anime_characters.anime_id = characters.id)').to_a
  Character Load (70.1ms)  SELECT "characters".* FROM "characters" WHERE (EXISTS (SELECT 1 FROM anime_characters WHERE anime_characters.anime_id = characters.id))

SQL 文字列が長い (せいで Rubocop :cop_tone2: に怒られかねない) のでヒアドキュメントを使って見やすくします。

[2] pry(main)> Character.where(<<~SQL)
[2] pry(main)*   EXISTS (
[2] pry(main)*     SELECT
[2] pry(main)*       1
[2] pry(main)*     FROM
[2] pry(main)*       anime_characters
[2] pry(main)*     WHERE
[2] pry(main)*       anime_characters.character_id = characters.id
[2] pry(main)*   )
[2] pry(main)* SQL
  Character Load (1.7ms)  SELECT "characters".* FROM "characters" WHERE (EXISTS (
  SELECT
    1
  FROM
    anime_characters
  WHERE
    anime_characters.character_id = characters.id
)
)

コード上は美しくなりましたが、残念なことにログ上でもこの SQL 文字列の部分だけ美しく改行されていて違和感があります…。

解決策

Active Support コア拡張機能の String#squish を使って複数行の SQL 文字列を 1 行にすることで、コード上の見た目を維持しつつ、ログ上では 1 行で表示されるようになりました :thumbsup:

[3] pry(main)> Character.where(<<~SQL.squish)
[3] pry(main)*   EXISTS (
[3] pry(main)*     SELECT
[3] pry(main)*       1
[3] pry(main)*     FROM
[3] pry(main)*       anime_characters
[3] pry(main)*     WHERE
[3] pry(main)*       anime_characters.character_id = characters.id
[3] pry(main)*   )
[3] pry(main)* SQL
  Character Load (1.0ms)  SELECT "characters".* FROM "characters" WHERE (EXISTS ( SELECT 1 FROM anime_characters WHERE anime_characters.character_id = characters.id ))