11 人が閲覧(直近 30 日) Ruby

RubyXLの使い方リファレンス|読み込み・セル編集・書式・保存の主要メソッドと注意点

RubyXLの使い方リファレンス|読み込み・セル編集・書式・保存の主要メソッドと注意点

RubyXLは、Excelの.xlsx(Office Open XML形式)をRubyで読み込み、書き換えて保存し直すためのgemです。2026年9月時点の最新版は3.4.38(2026年6月15日公開)で、MITライセンスです。本記事では主要メソッドを「読み込み」「書き込み・編集」「書式」「保存」に分け、Ruby 4.0.6とrubyXL 3.4.38で実行を確かめたコードで整理しました。require 'rubyXL' の大文字小文字、書式が消える add_cell の上書き、再計算されない数式など、公式READMEだけでは気づきにくい落とし穴もあわせて扱います。

まとめ:RubyXLの主要メソッドと押さえるべき注意点

  • 導入:gem install rubyXL。gem名もrequireも rubyXL(XLは大文字)。書式変更などを使うなら require 'rubyXL/convenience_methods' も必要
  • 読み込み:RubyXL::Parser.parse('book.xlsx')→workbook['シート名'] または workbook[0]→worksheet[行][列].value(行・列は0始まり)
  • 書き込み:新しいセルは add_cell(行, 列, 値)、既存セルの値だけを替えるなら change_contents(値)。既存セルへの add_cell は書式を消す
  • 保存:workbook.write('out.xlsx')。Railsで返すなら workbook.stream
  • 空の行・セルは nil:row&.[](列)&.value のように nil を前提に書く
  • できないこと:.xlsの読み書き、数式の計算。グラフ・画像・条件付き書式の作成は、READMEにある便利メソッドの対象外です。数万行規模の出力はメモリを大きく使うため caxlsx、読み取り専用なら roo が向く

最初に、gem名とrequireの大文字小文字を確認します。

RubyXLのインストールとrequireの書き方

gem名・requireの大文字小文字と「rubyXL」の指定

# 単体で入れる場合(gem名は大文字小文字を区別する)
gem install rubyXL

# Bundlerで管理する場合は Gemfile に追記して bundle install
gem 'rubyXL', '~> 3.4'

RubyGems上の登録名は rubyXL で、小文字の rubyxl は別名として扱われません。gem install rubyxl は「Could not find a valid gem ‘rubyxl’」で止まり、候補として rubyXL が示されます。Gemfileに gem 'rubyxl' と書いた場合も bundle install が「Could not find gem ‘rubyxl’ in any of the gem sources」で失敗します。Gemfileとbundle installの基本はgemとBundlerの使い方で整理しています。

require 'rubyXL'
# 書式変更・change_contents・セル結合・行の挿入などを使う場合に必要
require 'rubyXL/convenience_methods'

requireの側も同じです。macOSの標準ファイルシステムは大文字小文字を区別しないため require 'rubyxl' でも読み込めてしまいますが、大文字小文字を区別するボリュームで同じ行を実行すると cannot load such file -- rubyxl (LoadError) になりました。手元のMacで動いたコードがLinuxのサーバーやDockerコンテナで落ちる典型なので、最初から rubyXL と書いておきます。

convenience_methodsが必要になるメソッド

3.4.0で、データ構造本体と便利メソッドが分離されました(メモリ使用量を抑えるため)。require 'rubyXL' だけで使えるのは、Parser.parse・Workbook.new・add_worksheet・add_cell・value・write などの基本操作です。change_contents、フォント・塗り・罫線の変更、merge_cells、change_column_width、insert_row は rubyXL/convenience_methods を読み込まないと undefined method 'change_font_bold' for an instance of RubyXL::Cell のような NoMethodError になります。READMEでは convenience_methods/cell のように機能別に読み込む方法も案内されていますが、メモリを詰める必要がなければ一括で読み込めば足ります。

対応バージョンと依存gem

3.4.38の実行時依存は nokogiri(1.10.8以上)と rubyzip(3.2.2以上)です。rubyzipの要件は3.4.35(2025年11月6日公開)で ~> 2.4 から >= 3.2.2 に上がりました。rubyzip 3系はRuby 3.0以上を要求するため、Ruby 2系の環境で使えるのは3.4.34までです。Ruby本体の現行版とサポート期限はRubyの最新バージョンは4.0.7を参照してください。

RubyXLでExcelファイルを作成するコード

require 'rubyXL'
require 'rubyXL/convenience_methods'
require 'date'

workbook  = RubyXL::Workbook.new
worksheet = workbook[0]
worksheet.sheet_name = '売上'

%w[日付 商品 数量 単価 小計].each_with_index { |h, col| worksheet.add_cell(0, col, h) }

rows = [[Date.new(2026, 9, 1), 'りんご', 3, 120], [Date.new(2026, 9, 2), 'みかん', 5, 80]]
rows.each.with_index(1) do |(date, item, qty, price), r|
  worksheet.add_cell(r, 0, date).set_number_format('yyyy-mm-dd') # 表示形式を付けないと数値のまま
  worksheet.add_cell(r, 1, item)
  worksheet.add_cell(r, 2, qty)
  worksheet.add_cell(r, 3, price)
  worksheet.add_cell(r, 4, qty * price, "C#{r + 1}*D#{r + 1}") # 計算結果と数式を両方入れる
end

workbook.add_worksheet('集計')
workbook.write('sales.xlsx')

Workbook.new で作ったブックには「Sheet1」が1枚入っています。add_cell(行, 列, 値, 数式) の第4引数に数式を渡すと、第3引数の値は計算結果の控え(キャッシュ)として保存されます。RubyXLは数式を計算しないため、ここに正しい結果を入れておかないと、後でRubyXLで読んだときに値が空になります。

日付は注意が必要です。Date を add_cell しただけでは、セルには日付のシリアル値(2026年9月29日なら46294.0)が入り、表示形式が付きません。読み戻すと Float が返り、is_date? も真になりません。set_number_format('yyyy-mm-dd') のように日付の表示形式を付けたセルは、読み込み時に DateTime として返ります。

RubyXLでのExcelファイル読み込みとセル値の取得

シートの取得と行ごとのループ

require 'rubyXL'

workbook  = RubyXL::Parser.parse('sales.xlsx')
worksheet = workbook['売上'] || workbook[0] # シート名で探し、無ければ先頭シート

worksheet.each_with_index do |row, i|
  next if row.nil? # 何も入力されていない行は nil
  item = row[1]&.value
  sub  = row[4]&.value
  puts "#{i + 1}行目: #{item} #{sub}"
end

cell = worksheet.cell_at('A2') # Excel形式の参照(単一セルのみ)
p cell.value            # => #<DateTime: 2026-09-01T00:00:00+00:00 ...>
p cell.is_date?         # => true
p worksheet[1][4].formula&.expression # => "C2*D2"

先頭シートは workbook[0]、名前指定は workbook['売上'] です。存在しないシート名は例外にならず nil が返るので、上のように || で逃がすか、nil を検査します。cell_at('A2') はExcel形式の参照で1セルだけ取り出すメソッドで、A1:C3 のような範囲は受け付けません。行・列番号とセル参照の変換は RubyXL::Reference.ind2ref(1, 3)(結果は "D2")と ref2ind で行えます。

空の行・セルがnilになる疎配列への備え

ワークシートは行の疎配列、行はセルの疎配列です。一度も入力されていない行を worksheet[1][0] で参照すると undefined method '[]' for nil、行はあってもセルが無い位置では undefined method 'value' for nil で落ちます。Excelで作られた表は途中に空行や空セルがあるのが普通なので、ループでは next if row.nil?、セルは row[列]&.value と書くのが安全です。

結合セルも同じ理由で nil が出ます。A3:C3 を結合したセルの値は左上の A3 だけが持ち、B3・C3 は、結合前に値が無ければ nil です(結合前に値が入っていた場合、merge_cells はその値を消さずに残します)。結合範囲は worksheet.merged_cells で取得できるので、表を読み込むときは範囲を引いて左上の値を補います。

数式セルと日付セルで返る値

数式セルの value は、ファイルに保存されている直近の計算結果です。数式そのものは cell.formula&.expression で取れます(先頭の「=」は付きません)。Excelで保存したファイルなら計算結果が入っていますが、計算結果を持たずに生成されたファイルでは空文字が返ります。日付は前章のとおり、表示形式が日付のときだけ DateTime で返り、それ以外は数値です。

RubyXLを使ってExcelのセル内容を変更する方法

add_cellとchange_contentsの使い分け

require 'rubyXL'
require 'rubyXL/convenience_methods'

workbook  = RubyXL::Parser.parse('sales.xlsx')
worksheet = workbook['売上']

worksheet[1][2].change_contents(10)   # 値だけ替える。表示形式・太字・罫線は残る
# worksheet.add_cell(1, 2, 10)        # セルを作り直すので書式が既定に戻る

# 空セルは作成し、既存セルは書式を保って更新するヘルパー
# 数式セルでは既存の数式が残る。定数に置き換える場合は remove_formula も必要
def put_value(sheet, row, col, value)
  cell = sheet[row]&.[](col)
  cell ? cell.change_contents(value) : sheet.add_cell(row, col, value)
end
put_value(worksheet, 5, 1, '備考')

workbook.write('sales_edited.xlsx')

既存のテンプレートを開いて値を差し込む用途では、この使い分けが最も重要です。太字・塗り・表示形式「#,##0」を付けたセルに add_cell で書き込み直したところ、スタイル番号が0(既定)に戻り、太字も塗りも表示形式も消えました。同じ条件で change_contents を使うと、値だけが替わり書式は残りました。add_cell は第5引数 overwrite の既定が true で、セルを新しく作り直すためです。

空セルに change_contents は呼べない(nil のため)ので、上の put_value のように「既存セルなら change_contents、無ければ add_cell」と分けるのが実用的です。

行・列の挿入と削除で数式がずれる問題

insert_row(1)・delete_row(1)・insert_column・delete_column は、行や列を動かしても数式の参照先を書き換えません。READMEにも警告があり、実際に2行目の前へ1行挿入すると、4行目に移った小計セルの数式は C3*D3 のまま(本来は C4*D4)でした。insert_row は上の行の書式をコピーしますが、数式は手で直す必要があります。数式を含むテンプレートでは、行を挿入せず、あらかじめ明細行を確保した範囲へ書き込む設計のほうが壊れにくくなります。

RubyXLで使う書式設定メソッド:フォント・塗り・罫線・表示形式

require 'rubyXL'
require 'rubyXL/convenience_methods'

workbook  = RubyXL::Parser.parse('sales.xlsx')
worksheet = workbook['売上']

header = worksheet[0]
header.cells.each do |cell|
  cell.change_font_bold(true)
  cell.change_fill('dddddd')                   # 背景色は16進RGB
  cell.change_border(:bottom, 'thin')
  cell.change_horizontal_alignment('center')
end

worksheet[1][3].set_number_format('#,##0')     # 3桁区切り
worksheet.change_column_width(1, 20)            # B列の幅
worksheet.merge_cells('A5:E5')                  # 結合後の値は左上セルだけが持つ
worksheet.add_validation_list('B6', %w[りんご みかん]) # プルダウン

workbook.write('sales_styled.xlsx')

いずれも convenience_methods が必要です。よく使うものを対象別にまとめると次のとおりです。

目的 セル単位 行・列単位
太字 change_font_bold(true) change_row_bold(0, true)
フォント名 change_font_name('Meiryo') change_column_font_name(0, 'Meiryo')
文字色・背景色 change_font_color('ff0000')/change_fill('dddddd') change_row_fill(0, 'dddddd')
罫線 change_border(:top, 'thin') change_row_border(0, :bottom, 'thin')
配置 change_horizontal_alignment('center') change_column_horizontal_alignment(0, 'right')
表示形式 set_number_format('#,##0') -
折り返し change_text_wrap(true) -
幅・高さ - change_column_width(0, 20)/change_row_height(0, 30)
結合 - merge_cells('A5:E5')
プルダウン - add_validation_list('B6', [...])
リンク add_hyperlink('https://example.com') -

色は「dddddd」のような6桁の16進RGBで渡します。読み取り側は cell.is_bolded・cell.fill_color・cell.get_border(:top) などで現在の書式を確認できます。

罫線スタイル名の未検証とOOXMLの指定値

change_border の第2引数は、OOXML仕様(ST_BorderStyle)で定義された14種のいずれかにします。none・thin・medium・thick・double・hair・dotted・dashed・mediumDashed・dashDot・mediumDashDot・dashDotDot・mediumDashDotDot・slantDashDot です(rubyXLのソースが持つ定数一覧は mediumDashDotDot を欠いた13種)。READMEの例には hairline とありますが、仕様にもrubyXLの定数にもこの値はなく、正しくは hair です。RubyXLはここを検証しないため、'hairline' どころか 'foo' を渡してもエラーにならず、そのまま styles.xml に style="foo" と書き出しました。仕様外の値はExcel側で不正なファイルとして扱われかねないので、呼び出し側で仕様の14種から選ぶ定数を用意しておきます。

RubyXLでのファイル保存とストリーム出力

保存は workbook.write('out.xlsx')(save の別名)です。書き出せる拡張子は .xlsx・.xlsm・.xltx・.xltm の4種で、write('a.csv') は「Unsupported extension: .csv」で止まります。RubyXLは読み込んだ .xlsm のマクロ部分(vbaProject.bin)を保持したまま書き出す作りなので、マクロ付きブックの値だけを書き換える用途にも使えます(マクロを新たに作る機能はありません)。

# Railsのコントローラーでディスクに保存せず返す例
send_data workbook.stream.string,
          filename: 'sales.xlsx',
          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

Webアプリでファイルを返すときは、workbook.stream が返す StringIO の中身をそのまま送れば一時ファイルが要りません。逆向きの RubyXL::Parser.parse_buffer(バイト列) で、アップロードされたファイルをディスクに保存せず読み込めます。ただし、これはファイルを経由しないだけで、行ごとに少しずつ読む「ストリーミング」ではありません。ブック全体をメモリに展開する点は parse と同じです。

「cannot load such file — rubyXL」ほかエラーの原因と対処

RubyXLでよく出るエラーを、実際に発生させたメッセージで整理しました。

エラーメッセージ(抜粋) 原因 対処
cannot load such file -- rubyxl requireが小文字 require 'rubyXL'
cannot load such file -- rubyXL gem未導入/Bundler外で実行 bundle install後に bundle exec
Could not find gem 'rubyxl' Gemfileのgem名が小文字 gem 'rubyXL'
undefined method 'change_font_bold' 便利メソッド未読込 convenience_methodsをrequire
undefined method '[]' for nil 空行を参照 row&.[](列)
undefined method 'value' for nil 空セルを参照 cell&.value
Zip::Error ... not found ファイルパスの誤り パスを絶対パスで確認
Zip::Error ... signature not found .xls等のxlsx以外を読込 xlsxに変換してから読む
Unsupported extension: .csv 保存先の拡張子 .xlsx等で保存

見落としやすいのは、存在しないファイルを parse したときに Errno::ENOENT ではなく Zip::Error(「XLSX file format error: File nope.xlsx not found」)が返る点です。rescue Errno::ENOENT では捕まらないので、ファイルの有無は File.exist? で先に確かめるか、Zip::Error も捕捉します。

「cannot load such file — rubyXL」が大文字のまま出る場合は、gemが入っていないか、Bundlerの管理外で実行しています。bundle exec ruby script.rb で動くなら後者です。rbenvなどで複数のRubyを切り替えている環境では、gemを入れたRubyと実行しているRubyが別というケースも多く、ruby -v と gem list rubyXL を同じシェルで確認すると切り分けられます(rbenvとは?Rubyバージョン管理の仕組み)。

RubyXLでできないことと代替gemの選び方

数式の未計算とキャッシュ値・再計算属性

require 'rubyXL'
require 'rubyXL/convenience_methods'

workbook = RubyXL::Workbook.new
sheet = workbook[0]
sheet.add_cell(0, 0, 100)
sheet.add_cell(1, 0, 200)
sheet.add_cell(2, 0, 300, 'SUM(A1:A2)')  # 300は計算結果の控え(キャッシュ)
workbook.write('f.xlsx')

book = RubyXL::Parser.parse('f.xlsx')
book[0][0][0].change_contents(1000)       # A1を書き換えても
book.write('f2.xlsx')
p RubyXL::Parser.parse('f2.xlsx')[0][2][0].value # => 300(再計算されない)

# 開いたアプリに全再計算を求める印を付ける(ECMA-376 の fullCalcOnLoad)
book.calc_pr = RubyXL::CalculationProperties.new(full_calc_on_load: true)
book.write('f3.xlsx')

RubyXLは数式を保存・読み込みするだけで、評価はしません。上のコードでは A1 を100から1000へ書き換えて保存し直しても、SUM(A1:A2) のセルを読むと古い計算結果の300が返りました。RubyXLで値を書き換えたファイルの集計値をそのまま読み戻すと誤った数字を扱うことになるので、Ruby側で必要な値は Ruby で計算します。Excelで開いたときに再計算させたい場合は、ブックに fullCalcOnLoad(開いたときに全再計算を求めるOOXMLの属性)を付けます。

グラフ・画像・条件付き書式の扱いとxlsの非対応

READMEに載っている編集機能は、セル値・フォント・塗り・罫線・配置・表示形式・結合・プルダウン・ハイパーリンク・行列操作までで、グラフ・画像・条件付き書式を作る便利メソッドはありません。条件付き書式は、RubyXL::ConditionalFormatting や ConditionalFormattingRule といったOOXMLの要素に対応するクラスを直接組み立てれば書けますが、XML構造の知識が要ります。

既存ファイルに含まれるものについては、READMEは「構造をできるだけ保ったまま保存し直す」ことを方針に掲げています。caxlsxで棒グラフと条件付き書式を入れたxlsxをRubyXLで開き、セル値を1つ書き換えて保存したところ、グラフ(xl/charts/chart1.xml)も条件付き書式もそのまま残りました。「グラフ入りのテンプレートをExcelで作り、数値だけRubyXLで差し込む」使い方は成り立ちます。ただし完全な保持が保証されているわけではないので、使うテンプレートごとに保存後のファイルをExcelで開いて確認します。

旧形式の .xls はREADMEで非対応と明記されており、読み込むと前章の Zip::Error になります。xlsを扱うなら spreadsheet gem(1.3.5)か、roo と roo-xls の組み合わせを使います。

大量データでのメモリ使用量

RubyXLはブック全体をオブジェクトとしてメモリに展開します。50,000行×10列(文字列と整数を半々、50万セル)で計測すると、差は次のようになりました(macOS x86_64、Ruby 4.0.6、処理終了時の常駐メモリ)。

処理 gem(版) 常駐メモリ 処理時間(参考)
書き出し rubyXL 3.4.38 1,232MB 84秒
書き出し caxlsx 4.5.0 118MB 17秒
読み込み rubyXL 3.4.38 1,510MB 91秒
読み込み(行ストリーム) roo 3.0.0 55MB 53秒

処理時間は他のプロセスが動いている状態での値で、環境によって大きく変わります。比べるべきはメモリで、RubyXLは書き出しで caxlsx の約10倍、読み込みで roo の each_row_streaming の約27倍を使いました。メモリ上限が1GB前後のコンテナで数万行を扱うと、RubyXLは容量不足で落ちる可能性があります。Webリクエストの中で生成すると応答も遅れるので、大きな出力はSidekiqやActive Jobで非同期に回すのが定石です。

用途別のgemの選び分け

gem 最新版 対応形式 読み込み 書き出し 既存ファイルの編集
rubyXL 3.4.38 xlsx・xlsm ○ ○ ○
caxlsx 4.5.0 xlsx × ○(グラフ可) ×
roo 3.0.0 xlsx・ods・csv ○ × ×
spreadsheet 1.3.5 xls ○ ○ △(限定的)

RubyXLを選ぶ理由は「Excelで作ったファイルを開き、書式を保ったまま一部を書き換えて保存し直す」ことに尽きます。READMEも、主眼はExcelが作ったファイルを読み、小さな変更を加えて、構造をできるだけ保ったまま保存し直すことだと述べています。帳票テンプレートへの差し込みなら RubyXL、ゼロから大量の行やグラフを出力するなら caxlsx、取り込み処理のように読むだけなら roo です。新規の大量出力では caxlsx を優先し、既存テンプレートの編集が必要な場合は、想定する最大データでメモリ上限を超えないことを確認してRubyXLを採用します。

よくある質問

RubyXLの最新バージョンとRubyの対応範囲は?

2026年9月時点の最新は3.4.38(2026年6月15日公開)です。3.4.35以降は rubyzip 3.2.2以上に依存し、rubyzip 3系がRuby 3.0以上を要求するため、Ruby 3.0以上が前提です。Ruby 2系では3.4.34までを使います。

「rubyxl gem」と小文字で入れられますか?

入れられません。RubyGemsの登録名は rubyXL で、gem install rubyxl やGemfileの gem 'rubyxl' は「見つからない」エラーになります。requireも require 'rubyXL' と書きます。

RubyでExcelを扱うgemはどれを選べばよいですか?

既存のxlsxを開いて書式を保ったまま書き換えるなら rubyXL、新規に大量の行やグラフを出力するなら caxlsx、読み込むだけなら roo です。大量データでは実際の入力と実行環境でメモリを計測し、新規出力なら caxlsx、読み取り専用なら roo の行ストリーミングも比較します。

RubyXLで.xlsを.xlsxに変換できますか?

できません。RubyXLは.xlsを読み込めないためです。Rubyで完結させるなら spreadsheet gem や roo-xls で.xlsを読み、caxlsx か rubyXL で.xlsxとして書き出します。書式まで引き継ぎたい場合は、ExcelやLibreOfficeで.xlsxに保存し直してからRubyXLで開くほうが確実です。

RubyXLで数式の計算結果を取得できますか?

ファイルに保存されている直近の計算結果は value で取得できますが、RubyXL自身は計算しません。RubyXLで入力値を書き換えた後に読み戻すと、古い結果のままです。計算が必要な値はRuby側で求めるか、fullCalcOnLoad を付けてExcelで開いたときに再計算させます。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.07 テックブログ ファインズの不正アクセスと153万件の予約者情報|予約システムを使う店舗の報告と通知の手順
  2. 2025.08.14 コラム トラクションとは?ビジネスでの意味・指標の目安とgain tractionの使い方
  3. 2026.10.15 テックブログ 銀のさら不正アクセス:最大650万件の対象確認と窓口、パスワード変更・退会の手順
  4. 2026.10.19 テックブログ コミックシーモア不正アクセスで会員情報流出:再開時期・パスワード再設定と運営側のログ点検
  5. 2026.10.16 テックブログ バーガーキング情報漏洩どうしたらいい?約1,118万件の対象確認・補償・退会とメールの真偽

RELATED POSTS 関連記事

目次