基本

Ruby on RailsでSQLを直接操作する方法

Ruby on Railsでは通常、ActiveRecordを通じてデータベースを操作しますが、複雑なクエリや特殊な処理が必要な場合にはSQLを直接実行することもできます。この記事では、RailsでSQLを直接操作する方法と、ActiveRecordの基本的なCRUD操作、マイグレーションについて解説します。

基本的な使い方

ActiveRecord::Base.connection.executeメソッドを使って、SQLクエリを直接実行できます。

app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    sql = "SELECT * FROM companies"
    @companies = ActiveRecord::Base.connection.execute(sql)
  end
end
app/views/posts/index.html.erb
<% @companies.each do |company| %>
  <div><%= company['name'] %></div>
<% end %>

executeメソッドの戻り値はデータベースアダプタに依存しますが、通常はハッシュの配列のような形でアクセスできます。カラム名をキーとして各行のデータを取得します。

パラメータ付きSQL(SQLインジェクション対策)

SQLを直接書く場合、ユーザー入力をそのまま文字列連結するとSQLインジェクション攻撃のリスクがあります。必ずプレースホルダーを使用してください。

Ruby
# 危険な書き方(絶対にやらないこと)
sql = "SELECT * FROM users WHERE name = '#{params[:name]}'"

# 安全な書き方(プレースホルダーを使用)
sql = "SELECT * FROM users WHERE name = ?"
results = ActiveRecord::Base.connection.exec_query(sql, "SQL", [params[:name]])
注意

ユーザー入力を直接SQLに埋め込むと、悪意のあるSQLが実行される可能性があります。必ずプレースホルダー(?)やバインド変数を使用してSQLインジェクションを防いでください。

ActiveRecordによるCRUD操作

通常のデータ操作はActiveRecordのメソッドを使うのが推奨されます。SQLを直接書くよりも安全で読みやすいコードになります。

Ruby
# Create(作成)
company = Company.new(name: "テスト会社", address: "東京都")
company.save

# Read(読み取り)
companies = Company.all                    # 全件取得
company = Company.find(1)                  # IDで検索
results = Company.where(name: "テスト会社") # 条件で検索

# Update(更新)
company = Company.find(1)
company.update(name: "新しい会社名")

# Delete(削除)
company = Company.find(1)
company.destroy

ActiveRecordは内部でSQLを自動生成してくれるため、開発者がSQLを意識する必要がありません。また、SQLインジェクション対策も自動的に行われます。

テーブルの作成(マイグレーション)

Railsではデータベースのテーブル構造をマイグレーションファイルで管理します。テーブルの作成はモデルの生成コマンドで行います。

ターミナル
rails generate model Company name:string address:string phone:string

このコマンドにより、マイグレーションファイルとモデルファイルが自動生成されます。マイグレーションを実行してテーブルを作成します。

ターミナル
rails db:migrate

カラムの追加・変更

既存テーブルにカラムを追加するには、マイグレーションファイルを生成して実行します。

ターミナル
rails generate migration AddPhoneToCompanies phone:string
rails db:migrate
db/migrate/XXXXXX_add_phone_to_companies.rb
class AddPhoneToCompanies < ActiveRecord::Migration[7.0]
  def change
    add_column :companies, :phone, :string
  end
end

マイグレーションを元に戻したい場合は、rollbackコマンドを使います。

ターミナル
rails db:rollback
ポイント

SQLを直接実行するのは、ActiveRecordでは表現できない複雑なクエリ(複数テーブルの結合や集計関数など)が必要な場合に限定しましょう。通常のCRUD操作はActiveRecordを使うのが安全で効率的です。

まとめ

  • ActiveRecord::Base.connection.execute(sql)でSQLを直接実行できる
  • SQLインジェクション対策としてプレースホルダー(?)を必ず使用する
  • 通常のCRUD操作はActiveRecordのメソッド(findwherecreate等)を使う
  • テーブル構造はマイグレーションで管理する
  • rails db:migrateでマイグレーション実行、rails db:rollbackで元に戻す
  • SQL直接実行はActiveRecordで対応できない場合に限定する