ActiveRecord入門

SQLを意識せずにデータベースをRubyオブジェクトのように扱えるもの
>引用: [ActiveRecord入門 (全14回)-ドットインストール](http://dotinstall.com/lessons/basic_activerecord)

#1 ActiveRecordとは
Ruby on RailsのORマッパー
ObjectとRelational Data Baseをつなぐ

```bash
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

```sql:import.sql
create table posts( #テーブル名は英単語の複数形
	id integer primary key,
	title text,
	body text, 
	create_at, #日時
	updated_at　

);
```

```bash
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

```ruby:main.rb
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文を書かなくても操作できるのがメリット

```bash
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レコードを挿入してみよう
レコードの挿入方法について

```ruby:main.rb
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" )
#これなら１行で.newと.saveの機能がある


p Post.all
```

#5all,first,last,findをつかう

レコードを抽出するために基本的な命令について学ぶ

```ruby:main.rb
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をつかってみよう
```ruby:main.rb
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の使い方について解説していきます。

```ruby:main.rb
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は基本昇順）、３つ降順(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について見ていきます。

```ruby:main.rb
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 レコードを更新してみよう
```ruby:main.rb
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は関連するオブジェクトを削除することができるが遅い

```ruby:main.rb

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 バリデーションを使ってみよう
フィールドの妥当性をチェックするバリデーションの使い方について見ていきます。
ルールを付ける

```ruby:main.rb

require 'active_record'

ActiveRecord::Base.establish_connection(
	"adapter" =>"sqlite3",
	"database" => "./blog.db"
)

class Post < ActiveRecord::Base 
	タイトルは必ず付ける
	validates :title, :presence => true
	長さを５文字以上
	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)
関連するデータをまとめて扱うことができるアソシエーションについて見ていきます。まずはテーブルを用意します。

```sql:import.sql
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を表示してみます。

```ruby:main.rb
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も削除してみます。

```ruby:main.rb
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;
```