Upload
tomohiko-himura
View
4.214
Download
4
Embed Size (px)
DESCRIPTION
第二回 中国地方DB勉強会 http://local.aguuu.com/events/21550 O/R Mapping と ActiveRecord の話をする予定だったけど、時間が短くなったので、ActiveRecord の話はざっくりとなったセッションです。
Citation preview
O/R Mapping の話をするよ。特に ActiveRecord の話をしたかった。
2013-10-05 第2回中国地方DB勉強会
自己紹介
•火村 智彦
• Twitter eielh• GitHub eiel• Facebook 本名プレイ
hiroshima.rb 会場準備係
ベストツイート
対象者
• O/RM 使っている
対象者
• O/RM 使っているけど使ってないと主張する人
今日伝えたいこと
• O/RM 便利 手早く作るにはよい。
•使いこなしたいなら ソース読め
•データベースも勉強したほうがいい
• ActiveRecord は• SQL を意識して書きやすくなってる
アジェンダ
• O/RM について
• 復習的な感じに
• ActiveRecord について
• 基本
• その他の機能(ざっくりと)
注意事項
•気軽にマサカリ投げましょう
•たぶん会場の偉い人が教えてくれる
•それで盛り上げてください(遠い目)
注意事項
•気軽にマサカリ投げましょう
•たぶん会場の偉い人が教えてくれる
•それで盛り上げてください(遠い目)俺がそんなに
RDBに詳しい
わけがない
O/RM について
7,8年前のイメージ
• 気がついたら Web業界は データベースにデータ保存するのが当たり前になっていた
• 理由とかよくわからない
• データが消えにくい
• メモリが節約できる
O/RM 以前
• SQL を文字列で構築して
•カーソル (PL/SQLとか)
•全部取得(PHPとか)
•連想配列的なものとか配列に入って返ってくる
O/RM 以前
• SQL を文字列で構築して
•カーソル (PL/SQLとか)
•全部取得(PHPとか)
•連想配列的なものとか配列に入って返ってくる
意外とめんどくさい
こんな人はいますか?
• SELECT, UPDATE は書けるけど
• INSERT は書けない
もっと楽に書きたいだいたいデータが保存したいだけ
取り出しはみんな得意?
Object Relation Mapping(O/RM)
O/RM
• DBに取り出した時点で
• オブジェクトになってる
• メソッド定義していけば良い
• 保存は保存メソッド呼ぶだけ
• オブジェクトを作成すれば、DBへ挿入される
トレードオフ
• DBの力を引き出しづらい
•効率の良いSQLが書きづらい
•本来データベースでできることをプログラムする必要が生まれる
•関係データベースじゃなくてもよくね?
なんとなくのイメージPostgreSQL MySQL
なんとなくのイメージPostgreSQL MySQL
O/RM
なんとなくのイメージPostgreSQL MySQL
O/RM
NoSQL
そういえば
•WebObjects & CoreData
•すごいって聞いたけどどうなんだろう
戯言
• 関係データベースとプログラミング
• SQLは宣言的 <-> プログラミングは手続き
• SQLでも手続きは書ける (これは悪?)
• 純粋関数型言語…(宣言的)
• テーブルは集合(順番はない)
• 行は要素 -> カーソルで取得するとレコード
まとめ
• O/RM 使うと楽
• DBの力を引き出しにくい
ActiveRecordについて
基本的な話もしますがせっかくなので
使ってておもったことを書きます
基本的な話もしますがせっかくなので
使ってておもったことを書きます初心者向けの話にならないかもしれない
基本
• ルールを作ることで
• デフォルト設定ならほとんど何もいらない
• クラス名の複数形がテーブル名
• 自動的にセッタ、ゲッタが用意される
必要条件
•テーブルがある
• ActiveRecord::Base を継承したクラスがある
•クラス名の複数形がテーブル名である
基本 例
CREATE TABLE users ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(64));
class User < ActiveRecord::Baseend
基本
# hoge という名前のユーザを探す。なかったら作る。
user = User.where(name: 'hoge').first_or_create
# 名前を goro に変更
user.name = 'goro'
# 変更を保存
user.save
O/RM がなかったら# 疑似コードです。
query = "SELECT id, name FROM users WHERE name = 'hoge'"result = SQL.execute!(query)
if result.empty? create_query = "INSERT INTO users VALUES ('hoge')" SQL.execute!(create_query) result = SQL.execute!(query)end
update_query = "UPDATE users SET name = 'goro' where id = ?"user = result[0]SQL.execute!(update_query, user[:id])
フォームとカラム
• テーブル設計について
• 必要なものだけ作るのが楽
• リファクタリングでカバー
• テストコードがあればどうにでもなる
• トレードオフ
• マイグレーションをがんばる
フォームとカラム
• カラムはフォームの項目に1対1に対応させると楽
• 画面をつくって入力したい項目を考えればよい
• 補佐的なカラムが必要なら追加すればいい
• 最適化が必要になったら
• その時がんばればいい
• テストコードないとつらい…
DB設計
•しっかり設計したい場合
• ActiveRecordを使わない選択
• Rail への乗り方を熟知しておく選択
phpMyAdmin病
• phpMyAdmin を使いたがる 病
•状態をみたい
•テストするのに値を書き換えたい
• rails console を生かせ
rails console を使う
• 状態をみたい
• 簡単に見えようにメソッドを用意しよう
• テストするデータつくりたい
• ファクトリメソッドを用意しよう
• テストコードかけ
rails console を使う
• 状態をみたい
• 簡単に見えようにメソッドを用意しよう
• テストするデータつくりたい
• ファクトリメソッドを用意しよう
• テストコードかけ
他の人が同じことをする時ために手順をわかりやすくしておこう
くりかえし実行しやすくしよう
ソース読め
• 実は意外と難しくない
• ActiveRecord::Base は mixin してるだけ
• lib/active_record/base.rb
• モジュール間はほとんど直交してる
ソース読め read.rb
# 自動で定義されるゲッタの中身
# lib/active_record/attribute_methods/read.rb# `#define_method_attribute` より
read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) }
ソース読め read.rb
• read_attribute(attr_name) で値が取れそう
• 値がなかったらなんかするっぽい
• read_attribute を見ると…
• @attributes ってところに値があるっぽい
ソース読め read.rb
• read_attribute(attr_name) で値が取れそう
• 値がなかったらなんかするっぽい
• read_attribute を見ると…
• @attributes ってところに値があるっぽい
ごめん! そんなに簡単じゃなかった!!
以下、時間が余れば
制約
• なるべく設定したい
• データの整合性が楽に保てる
• しかし
• エラーが起きたときのコードが別途必要
• エラーがSQLがわからないとわかりにくい
特に NOT NULL 制約
•基本的に自分で付ける必要がある
•できるだけかきたい
•その NULLは本当に必要なNULL?
•プログラム的には扱いにくくなる
特に外部キー制約
•複雑なシステムほどあるといい
•しかし
•テストコード書くのは大変になる
•特に実行に時間がかかる
クエリビルダ
• SQLを構築するメソッドを呼ぶと
• ActiveRecord::Relation というオブジェクトが返ります
• これはSQLの構築の途中の状態
• to_a などを呼ぶことで SQL が実行される
クエリビルダ 例class User < ActiveRecord::Base scope :admin, -> { where(type: 'admin') } scope :rank_max, -> { where(rank: 5) }end
User.where(type: 'admin') .to_sql # => where type = 'admin'User.admin.to_sql # => where type = 'admin'User.admin.rank_max.to_sql # => where type = 'admin' # and where ranke = 5
クエリビルダ
•クエリに名前をつけて
•クエリ同士を合成できる
クエリビルダ発展
•サブクエリとしても使える
•他のテーブルの条件も使いたい
•merge メソッドで合成
その他
•もっとクエリビルダ
•リレーション
• arel•大小比較ができない!
• squeel 使うといいよ
ご清聴ありがとうございました。