Sequel、DataMapper、Active Recordなど、Ruby の ORM のいずれかを調べることを強くお勧めします。
独自の DSL を使用してクエリを抽象化し、ロジックに集中できるようにすることで、作業が大幅に簡素化され、フィールドの内容が Ruby のネイティブ オブジェクトとして返されます。あなたが見ているような問題はもうありません。
これらのツールは、手動で生成するものと同等の SQL を生成します。彼らが間違ったことをするように一生懸命働かなければならず、彼らが生み出すものを改善できることはめったにありません.
さらに、接続 DSN を変更するだけで、まったく異なるデータベース マネージャーに切り替えることができます。データベース マネージャーはアーキテクチャの違いを認識し、その新しい環境に最適化された SQL を生成します。MySQL、PostgreSQL、Oracle、または SQLite ドライバーと直接対話してみてください。
Sequel と SQLite を使用したコードの例を次に示します。
require 'sequel'
DB = Sequel.sqlite # memory database
DB.create_table :items do
primary_key :id
String :name
Integer :number
Float :price
end
items = DB[:items] # Create a dataset
# Populate the table
items.insert(:name => 'abc', :number => 1, :price => rand * 100)
items.insert(:name => 'def', :number => 3, :price => rand * 100)
items.insert(:name => 'ghi', :number => 7, :price => rand * 100)
# Print out the number of records
puts "Item count: #{ items.count }"
# Print out the values:
items.each do |i|
puts i
end
実行後にこれを返します:
Item count: 3
{:id=>1, :name=>"abc", :number=>1, :price=>48.3673258126733}
{:id=>2, :name=>"def", :number=>3, :price=>41.87676958348104}
{:id=>3, :name=>"ghi", :number=>7, :price=>62.54605297923891}
行を抽出するループ内:
items.each do |i|
puts i
end
ループを通過するたびi
にハッシュが生成されるため、個々のフィールドを簡単に抽出できます。コードを再度実行します。
>> item = items.first
{
:id => 1,
:name => "abc",
:number => 1,
:price => 70.81654554223003
}
>> item.class
Hash < Object
integer と float の値が期待どおりであることに注意してください。(「価格」フィールドの値はランダムであるため、変動します。)
Rails の場合、ORM である Active Record に遭遇します。Rails の外部で Active Record を使用することは可能ですが、Rails のフレームワークを対象としています。私のチームでは、DB とのやり取りに Sequel を広く使用しています。私のコード パートナーは最近、接続文字列を変更し、セットアップした移行を実行し、データの再読み込みを開始することで、MySQL ベースのデータベースから PostgreSQL への完全な変換を約 1 時間で完了しました。特に SQL を記述する必要がないため、非常に簡単であることに非常に満足していました。
Sequel には、IRB に基づいて構築されたコマンドライン バージョンが付属しています。データベースに対話的にクエリを実行し、それらを変更し、その内容を覗き見することができます。また、何が生成されるかを確認するのにも最適な方法です。
Your database is stored in DB...
Welcome to SEQUEL. You are using ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]. Have fun ;)
>> require 'logger'
true
>> DB.loggers << Logger.new(STDOUT)
[
[0] #<Logger:0x007f7fe41dd880 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0x007f7fe41dd858 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x007f7fe41dd808 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDOUT>>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x007f7fe41dd7e0 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x007f7fe41dd790>>>>
]
>> DB.create_table :items do
> primary_key :id
| String :name
| Integer :number
| Float :price
| end
I, [2013-10-06T09:51:55.752052 #6721] INFO -- : CREATE TABLE items (id integer PRIMARY KEY AUTOINCREMENT, name varchar(255), number integer, price double precision)
nil
>> items = DB[:items]
#<Sequel::Mock::Dataset: "SELECT * FROM items">
>> items.insert(:name => 'abc', :number => 1, :price => rand * 100)
I, [2013-10-06T09:52:15.421974 #6721] INFO -- : INSERT INTO items (name, number, price) VALUES ('abc', 1, 22.32640955200822)
nil
>> items.insert(:name => 'def', :number => 3, :price => rand * 100)
I, [2013-10-06T09:52:15.432649 #6721] INFO -- : INSERT INTO items (name, number, price) VALUES ('def', 3, 43.182983199793824)
nil
>> items.insert(:name => 'ghi', :number => 7, :price => rand * 100)
I, [2013-10-06T09:52:15.441312 #6721] INFO -- : INSERT INTO items (name, number, price) VALUES ('ghi', 7, 67.81054007143193)
nil
>> items.count
I, [2013-10-06T09:52:23.683121 #6721] INFO -- : SELECT count(*) AS count FROM items LIMIT 1
0