SQLを意識せずにデータベースをRubyオブジェクトのように扱えるもの
#1 ActiveRecordとは
Ruby on RailsのORマッパー
ObjectとRelational Data Baseをつなぐ
Mac-no-MacBook-Pro:sinatora_lessons Mac$ gem list activerecord
*** LOCAL GEMS ***
activerecord (4.2.0)
Mac-no-MacBook-Pro:sinatora_lessons Mac$ gem list sqlite3
*** LOCAL GEMS ***
dbd-sqlite3 (1.2.5)
sqlite3 (1.3.10)
sqlite3-ruby (1.3.3)
Mac-no-MacBook-Pro:sinatora_lessons Mac$ gem -v
2.2.2
#2データベースの準備をしよう
ar_lessons
┣blog.db
┗import.sql
create table posts( #テーブル名は英単語の複数形
id integer primary key,
title text,
body text,
create_at, #日時
updated_at
);
Mac-no-MacBook-Pro:sinatora_lessons Mac$ cd ../
Mac-no-MacBook-Pro:Mac Mac$ cd ar_lessons
Mac-no-MacBook-Pro:ar_lessons Mac$ sqlite3 blog.db
SQLite version 3.8.5 2014-08-15 22:37:57
Enter ".help" for usage hints.
Mac-no-MacBook-Pro:ar_lessons Mac$ sqlite3 blog.db
SQLite version 3.8.5 2014-08-15 22:37:57
Enter ".help" for usage hints.
sqlite> .read import.sql
sqlite> .schema
CREATE TABLE posts(
id integer primary key,
title text,
body text,
create_at,
updated_at
);
sqlite> select * from posts
...> ;
sqlite>.exit
テーブルが完成したので次回ActiveRecordから扱う方法
#3 はじめてのAR
RubyファイルからARをつかってテーブルを操作
ar_lessons
┣main.rb
┣blog.db
┗import.sql
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
#これでARとRubyのオブジェクトが紐付けられた
post = Post.new(:title => "title1",:body => "hello" )
post.save
p Post.all
SQL文を書かなくても操作できるのがメリット
sqlite> drop table posts
...> ;
sqlite> .schema
sqlite> .read import.sql
sqlite> .schema
CREATE TABLE posts(
id integer primary key,
title text,
body text,
created_at,
updated_at
);
sqlite> .exit
Mac-no-MacBook-Pro:ar_lessons Mac$ ruby main.rb
#<ActiveRecord::Relation [#<Post id: 1, title: "title1", body: "hello", created_at: "2015-02-13 15:08:28.961826", updated_at: "2015-02-13 15:08:28.961826">]>
#4レコードを挿入してみよう
レコードの挿入方法について
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
#これでARとRubyのオブジェクトが紐付けられた
#post = Post.new(:title => "title1",:body => "hello" )
=begin
post = Post.new
post.title = "title2"
post.body = "hello2"
post.save
=end
=begin
post = Post.new do |p|
p.title = "t"
p.body = "h"
end
post.save
=end
Post.create(:title => "title4",:body => "hello4" )
#これなら1行で.newと.saveの機能がある
p Post.all
#5all,first,last,findをつかう
レコードを抽出するために基本的な命令について学ぶ
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
#これでARとRubyのオブジェクトが紐付けられた
1.p Post.all
2.p Post.first
3.p Post.last.title
4.p Post.find(3)
5.p Post.find_by_title("title2")
6.p Post.find_by_title_and_id("title2",2)
findを使えば任意のレコードを抽出できる
#6whereをつかってみよう
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
#これでARとRubyのオブジェクトが紐付けられた
1.p Post.where(:title => "title1",:id => 1)
2.p Post.where(:title => ? and id = ?,"title1",1)
3.p Post.where(:title => :title and id = :id,{:title => "title1",:id => 1})
4.p Post.where("id > ?",2)
5.p Post.where("body like ? ,"hello%")
#7order,limit,scopeを使ってみよう
並び替えや抽出件数を指定する方法、抽出条件を定義できるscopeの使い方について解説していきます。
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
AcriveRecord::Base.logger = Logger.new(STDOUT)
class Post < ActiveRecord::Base
scope :top3,order(created_at).limit(3)
end
#これでARとRubyのオブジェクトが紐付けられた
1.p Post.where(:id => 1..3)
2.p Post.where(:id => [1,3])
並び替え(orderは基本昇順)、3つ降順(desc)
3.p Post.order("id desc").limit(3)
抽出条件をscopeで定義
4.p Post.top3
条件を組み立てているときにどういうsqlを組み立てているか確認できる5.AcriveRecord::Base.logger = Logger.new(STDOUT)
#08 first_or_createを使ってみよう
今まではレコードの挿入と抽出してきた
抽出結果がなかったらレコードの新規作成をしてくれるfirst_or_createについて見ていきます。
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
title4がある場合は表示
1.p Post.where(:title => "title4").first_or_create
title5がない場合は新規作成
2.Post.where(:title => "title5").first_or_create
3.p Post.all
4.Post.where(:title => "title6").first_or_create do |p|
p.body = "hello6"
end
5.p Post.all
#09 レコードを更新してみよう
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
end
post = Post.find(1)
1.=begin
post.title = "(new)title"
post.save
=end
2.post.update_attribute(:title,"(new2)title")
3.post.update_attributes(:title=>"(new2)title",":body"=>"")
4.Post.where(:id => 1..2).update_all(:title =>"",:body => "")
p Post.all
#10 レコードを削除してみよう
レコードを削除するdelete、destroyについて見ていきます。
deleteは単にレコードの削除で早い
destroyは関連するオブジェクトを削除することができるが遅い
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base
end
1.Post.where(:id =>1..2).delete_all
2.Post.find(3).destroy
複数削除は_all
を付ける
delete from developer_games where id > 92;
#11 バリデーションを使ってみよう
フィールドの妥当性をチェックするバリデーションの使い方について見ていきます。
ルールを付ける
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base
タイトルは必ず付ける
validates :title, :presence => true
長さを5文字以上
validates :body, :length => {:minimum => 5}
これを満たさない場合はsaveされない
end
post = Post.new(:body =>"123")
post.save
エラー表示
1.post.save!
2.if !post.save
p post.errors.messages
end
#12 アソシエーションを使ってみよう (1)
関連するデータをまとめて扱うことができるアソシエーションについて見ていきます。まずはテーブルを用意します。
drop table if exists posts;
create table posts(
id integer primary key,
title text,
body text,
created_at,
updated_at
);
insert into posts(id,title,body) values (1,"title1","hello1");
insert into posts(id,title,body) values (2,"title2","hello2");
insert into posts(id,title,body) values (3,"title3","hello3");
drop table if exists comments;
create table comments(
id integer primary key,
post_id integer,
title text,
body text,
created_at,
updated_at
);
insert into posts(id,post_id,body) values (1,1,"comment1");
insert into posts(id,post_id,body) values (2,1,"comment2");
insert into posts(id,post_id,body) values (3,2,"comment3");
insert into posts(id,post_id,body) values (4,2,"comment4");
insert into posts(id,post_id,body) values (5,3,"comment5");
insert into posts(id,post_id,body) values (6,3,"comment6");
#13 アソシエーションを使ってみよう (2)
アソシエーションを設定し、抽出したpostに関連するcommentを表示してみます。
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
has_many :comment
end
class Comment < ActiveRecord::Base #import.sqlのテーブル名commentsを大文字、単数形に変える
belongs_to :post
end
#postとcommentsの関係が一対多
post = Post.find(1)
post.comments.each do |comment|
p comment.body
end
#14 アソシエーションを使ってみよう (3)
postを削除したときに、それに関連したcommentも削除してみます。
require 'active_record'
ActiveRecord::Base.establish_connection(
"adapter" =>"sqlite3",
"database" => "./blog.db"
)
class Post < ActiveRecord::Base #import.sqlのテーブル名postsを大文字、単数形に変える
has_many :comment, :dependent => :destroy
end
class Comment < ActiveRecord::Base #import.sqlのテーブル名commentsを大文字、単数形に変える
belongs_to :post
end
#postとcommentsの関係が一対多
p Post.all
p Comment.all
Post.find(1).destroy
#関連するモデルを消すのでdestroy
p Post.all
p Comment.all
#csv出力
sqlite> .mode csv
sqlite> .output game.csv
sqlite> select * from developer_games;