Parse A Csv String Into An Array Of Hashes With Headers In Ruby
Uploaded spreadsheets and API exports arrive as CSV strings. Converting them into an array of hashes keyed by header name makes the rest of the code readable — row[:email] instead of row[3].
Description
Ruby’s csv library handles quoting, embedded commas, and newlines inside fields, which is why hand-splitting on commas breaks on real data.
headers: true reads the first line as headers. header_converters: :symbol downcases them and turns them into symbols. map(&:to_h) converts each CSV::Row into a plain hash.
Add converters: :numeric to coerce numbers automatically, and strip whitespace with a custom converter — exported CSVs are full of stray spaces.
Sample input:
csv = "Name,Email,Age\nAda Lovelace,[email protected],36\n\"Smith, John\",[email protected],42\n"
Sample Output:
# => [{ name: "Ada Lovelace", email: "[email protected]", age: 36 },
# { name: "Smith, John", email: "[email protected]", age: 42 }]
Answer
require "csv"
def parse_csv(text)
CSV.parse(
text,
headers: true,
header_converters: :symbol,
converters: [:numeric, ->(field) { field.is_a?(String) ? field.strip : field }]
).map(&:to_h)
end
parse_csv(csv)
# => [{ name: "Ada Lovelace", email: "[email protected]", age: 36 }, ...]
# Stream a large file instead of loading it into memory
CSV.foreach("orders.csv", headers: true, header_converters: :symbol) do |row|
Order.create!(row.to_h.slice(:sku, :quantity))
end
# Custom delimiter and encoding
CSV.parse(text, headers: true, col_sep: ";", encoding: "bom|utf-8")
# Reject rows where every value is blank
parse_csv(csv).reject { |row| row.values.all? { |v| v.to_s.strip.empty? } }
Check viewARU - Brand Newsletter!
Newsletter to DEVs by DEVs - boost your Personal Brand & career! 🚀