Ruby on Railsを基礎から学ぶ 第7回
〜ファインダーメソッドとSQL〜
今回はファインダーメソッドとSQLをやります。
Railsでは、モデルとDBのテーブルががっちりくっついていて、javaやVisual Studioのときのように、細かなSQLの整備や隠蔽が不要です。このあたりは大変すっきりしています。
また次回から始まるresourseの概念では、SQLを直接触らないRails特有のCRUD(追加・読込・更新・削除)の書き方に馴れなければなりません。
今回は内容的には結構暇ですがちゃんと見てくれるとありがたいです。
では、本題に入ります。
注意.Config\application.rbのconfig.active_record.whitelist_attributes
えーと、今日はいきなりわき道的な話になりますが、表題の通り、configフォルダの中に、
application.rbという重要なファイルがあります。
このファイルは重要なファイルですが、英語がいっぱい書いてあり、初心者にはいまいちよくわからないと思うので酢。
モデルだけでなく、パッケージ全体の設定の肝であることがわかってきますので、今回はここで少しお時間をください。。
さて、このファイルの中に、
# config.active_record.whitelist_attributes =
true
という項目があって、コメントアウトはされていますが、=trueが事前に設定されています。
これをfalseにするか、上のようにコメントアウトしておかないと以下のメッセージが消えません。
この行のコメントを外すと、レコード更新を行う際に、ハッシュ(list)での更新が行えない状態になります。
たとえば、nameを更新するついでにハッシュでadministarator権限などもいっしょに更新できるように追加し、権限を取得した上でアプリに悪さをするといった悪質なサイトへの攻撃が行えるというわけです。
この行がコメントされていないと、現在はエラーが出ることがあります。
いまはまだローカルでの練習ですし、ハッシュを使って、レコードを更新しないと不便ですので、、コメントした状態でよいです。
※もし、trueだったら、コメントアウトしておいてください。設定は章が進めば戻すことになります。
警告メッセージの発生した画面
また、railsコンソールを立ち上げたときに、以下のようなメッセージが出た場合も同様です。
SECURITY
WARNING: No secret option provided to Rack::Session::Cookie. This poses
a security threat. It is strongly recommended that you provide a secret
to prevent exploits that may be possible from crafted cookies.
This will not be supported in future versions of Rack, and future
versions will even invalidate your existing user cookies. |
ちょっと脅かしてしまいましたが、本題です。
便利なモデル操作の学習をしましょう。
1.Railsコンソールからテーブルを検索する
Railsコンソールというのがあり、ここから、モデルを直接操作できます。
>rails console
または>rails cでもいけます。
下のように、irb(main):001:0>という形で、rubyコマンドプロンプトとは異なるコマンド待ち状態になります。
この状態で、あずは全部出してみましょう。
ruby
1.9.3p392 (2013-02-22) [i386-mingw32] C:\Documents
and Settings\Adimin>cd \dragon C:\dragon>rails console Loading
development environment (Rails 4.0.0.rc1) irb(main):001:0> |
@Allメソッド(全件出力)
これは、該当のモデルの中身全部を出します。
こんなメソッドを打つのは、出来立てのモデルか初心者くらいしかいません。
このようにずらずらと出てしまいます。
irb(main):001:0>
Member.all [1m[36mMember Load (203.1ms)[0m [1mSELECT "members".* FROM
"members"[0m ð
#<ActiveRecord::Relation
[#<Member id: 1, number: 1, name: "Thomas", full_name: nil,
email: ・・・(略)およそ30行くらい・・・ irb(main):002:0> |
Aall.map(&:カラム名)
今度はテーブルの特定の項目の値、全てを取り出します。
たとえば、idだったらそんなすごい量にはならないかもしれませんが、
何万件もあるデータではやはり使うのはキツイですね^^
irb(main):002:0>
Member.all.map(&:id) [1m[35mMember Load (0.0ms)[0m SELECT "members".* FROM
"members" => [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 4] |
Bfindメソッド
これはファインダーメソッドではありません。
しかし、よく使う初歩的な検索メソッドです。その名前の通り、引数の値で、idを検索します。
黒字の部分がメソッドの実行と、出力されたデータの中身です。
irb(main):003:0>
Member.find(3) [1m[36mMember Load (109.4ms)[0m [1mSELECT "members".* FROM
"members" WHERE "members"."id " = $1
LIMIT 1[0m [["id", 3]] => #<Member id: 3, number: 11, name:
"Jiro", full_name: "鈴木 次郎",
email: "Jiro@example.com", birthday: "1981-12-01",
gender: 0, administrator: false, created_at: "2013-05-15 08:05:16",
up dated_at: "2013-05-15 08:05:16",
phone: nil> |
Cインスタンスの生成
今使用しているのはrailsコンソールです。
コマンドプロンプトでも、git bashでも、もちろんポスグレ(postgreSQL)のコマンド画面でもありません。
Railsなのです。
今まで打ってきたメソッドはそのままrailsプログラミングに使えます。
そこで、Memberモデルを実体化してハッシュ変数に格納してみます。
member = Member.find(3)
こうすることで、id=3の会員のデータをmemberという実体化した変数に格納できるのです。
このとき、idからadmin権限まで、全てハッシュの形で持っています。
このようにハッシュでレコードごとやりとりするのはたしかに危険かもしれません。
回避方法については、後述しますので、今はこのまま続けます。
このあとは、そのまま
member.email
のようにすることで、その項目だけ抜き出すなどが可能です。
下のリストは、今の過程を貼り付けたものです。
irb(main):005:0>
member = Member.find(3) [1m[35mMember Load (0.0ms)[0m SELECT "members".* FROM
"members" WHERE "members"."id" = $1 LIMIT 1 [["id", 3]] =>
#<Member id: 3, number: 11, name: "Jiro", full_name: "鈴木 次郎", email:
"Jiro@example.com", birthday: "1981-12-01",
gender: 0, administrator: false, created_at: "2013-05-15 08:05:16",
up dated_at:
"2013-05-15 08:05:16", phone: nil> irb(main):006:0>
member.email =>
"Jiro@example.com" |
D存在しないレコードへの対応
検索したときに、そのidのレコードが無い場合、どうするのでしょうか?
find_by_idメソッドであればnilが返りますので、これを用いてそのあと条件分岐などをさせることができます。
(123)などもちろんまだありません。
下のようになります。
irb(main):007:0>
Member.find_by_id(123) [1m[36mMember Load (0.0ms)[0m [1mSELECT "members".* FROM
"members" WHERE "members"."id" = 123 LIMIT
1[0m => nil |
2.ファインダーメソッドで検索する
ようやく、ファインダーメソッドになりました。
ファインダーメソッドはたくさんあります。
概ね他の言語でDBにつないで、ゴリゴリSQLを書くタイミングで、
railsは便利で高度なメソッドが多数用意されているのです。
それがファインダーメソッドです。
@whereメソッド
これはそのまんまのSQLにおけるwhere句のようなものです。
下のように範囲指定(between)に書けば、numberが12から14のものを検索できます。
irb(main):008:0> Member.where(number:12..14) [1m[35mMember Load (0.0ms)[0m SELECT "members".* FROM
"members" WHERE ("members"."number" BETWEEN 12 AND 14) =>
#<ActiveRecord::Relation [#<Member id: 4, number: 12, name:
"Hana", full_name: "高橋
花", em ail:
"Hana@example.com", birthday: "1981-12-01", gender: 1,
administrator: false, created_at: " 2013-05-15
08:05:16", updated_at: "2013-05-15 08:05:16", phone: nil>,
#<Member id: 5, number: 1 3, name:
"John", full_name: "田中
太郎", email: "John@example.com", birthday:
"1981-12-01", gen der: 0,
administrator: false, created_at: "2013-05-15 08:05:16",
updated_at: "2013-05-15 08:05: 16",
phone: nil>, #<Member id: 6, number: 14, name: "Mike",
full_name: "佐藤 次郎", email: "Mik e@example.com",
birthday: "1981-12-01", gender: 0, administrator: false,
created_at: "2013-05-1 5
08:05:16", updated_at: "2013-05-15 08:05:16", phone: nil> |
Aoederメソッド
これも、ほぼ予想がつくと思いますが、並べ替えをしてくれます。
members = Member.where(gender:1).order("number DESC")
DESC:逆順(大きい数値から)、 ASC:正順(小さい数字からで、デフォルトはこっちなので、省略可能です) |
いま、上のように打ってみました。
ここで、membersという複数形の変数を作って、gender:1(つまり女性)のレコードを、
ギルドナンバーがDESC(降順、逆順)で、並べ替えた結果を出力します。
この結果は、もちろん複数レコードが予想されますから、membersというハッシュに複数行入れてしまうわけです。
中盤にQUERY PLANというのが表示されます。これで、レコード処理の流れが見えます。
どうやら、4件のようですね。
Loading
development environment (Rails 3.2.1) irb(main):001:0>
members =
Member.where(gender:1).order("number DESC") [1m[36mMember Load (531.2ms)[0m [1mSELECT "members".* FROM
"members" WHER nder" =
1 ORDER BY number DESC[0m [1m[35mEXPLAIN (31.2ms)[0m EXPLAIN SELECT "members".*
FROM "members" WHERE der" =
1 ORDER BY number DESC EXPLAIN
for: SELECT "members".* FROM "members" WHERE
"members"."gender" = 1 ORD SC
QUERY PLAN ----------------------------------------------------------------- Sort (cost=10.39..10.39 rows=1 width=2097)
Sort Key: number
-> Seq Scan on
members (cost=0.00..10.38 rows=1
width=2097)
Filter: (gender = 1) (4 rows) =>
[#<Member id: 12, number: 45, name: "sakachan", full_name:
"坂城つかさ",
emai :
"1994-02-01", gender: 1, administrator: false, created_at:
"2013-05-29 08:19:1 "2013-05-29 08:19:10", phone:
nil>, #<Member id: 10, number: 18, name: "Mary", 藤 花子",
email: "Mary@example.com", birthday: "1981-12-01",
gender: 1, administ reated_at:
"2013-05-15 08:05:16", updated_at: "2013-05-15 08:05:16",
phone: nil> ・・・(略)・・・ irb(main):002:0> |
Bファインダの結果にfindをかける
以下のようなことが可能です。
先ほどのmembersという検索結果に対して、さらにfindを使って、検索をかけましょう。
members.find(12)
上記の検索結果から、id=12のsakachanという人がいるようですので、それを直接指定して、検索してみましょう。
irb(main):002:0>
members.find(12) [1m[36mMember Load (125.0ms)[0m [1mSELECT "members".* FROM
"members" WHERE "members"."ge nder"
= 1 AND "members"."id" = $1 ORDER BY number DESC LIMIT
1[0m [["id", 12]] => #<Member id: 12, number: 45, name:
"sakachan", full_name: "坂城つかさ", email: "", birthday: "1994-02-01", gender: 1,
administrator: false, created_at: "2013-05-29 08:19:10",
updated_at: "2013-05-29
08:19:10", phone: nil> irb(main):003:0> |
このように、検索結果を一度格納して、さらに何度もファインダメソッドをかけられるところは
Railsの大変便利なところです。
このまま、membersに対して、SQLを使ってみることにしましょう。
3.SQLを使用した検索をする
既に気付いている方も多いと思いますが、モデルでの操作は、結果を出す前に、SQLを自動的に発行しているのです。
Railsはこのように、SQLを隠蔽する言語ではないようです。
皆さんの中にもSQLインジェクション攻撃という言葉を聞いたことがあると思いますが、
このようなデータベースの接続を伴うユーザ操作では、SQLに対してナイーブになってしまうのが実情です。
便利さと安全性の両方を実現させねばならない状況になってきつつあるrailsですが、
きっとこの苦難もうまく乗り切ってくれるでしょう。
品代に入って、SQLです。
SQLは一般的に広く使われており、DB設計書や詳細設計所などでも、SQLをそのまま列挙しているプロジェクトもあります。
また、SQLに馴れている人は、そのほうがいいと思うので、直接SQLを入力する方法を書きます。
members.find_by_sql("SQL文”)
実際に打ったものが下のリストです。
ここでも、前の項で作ったmembersからSQLを実行しています。
irb(main):003:0>
members.find_by_sql("select *
from members where name = 'sakachan'") [1m[35mMember Load (93.8ms)[0m select * from members where name =
'sakachan' =>
[#<Member id: 12, number: 45, name: "sakachan", full_name:
"坂城つかさ",
email: "", birthday :
"1994-02-01", gender: 1, administrator: false, created_at:
"2013-05-29 08:19:10", updated_at: "2013-05-29 08:19:10", phone:
nil>] irb(main):004:0> |
ということで、おしまいです。
ファインダメソッドは、モデルのActiveRecordというクラスに入っています。
調べてみると、まとまりの良いサイトが少ないので、このページで少しずつ増やして生けたら十もいます。
Rails4.0では、レコードの更新に権限が必要となったようです。
このあたりもお伝えしていければと思います。
次回は、いよいよresourseに入ります。
今回はいまいちぱっとしなかった方も今はそれでいいです。
また戻って必要なときに見返してください。
■ 参考テキスト■
サ改定新版 基礎 Ruby on Rails オイアクス監修 インプレスジャパン
■ 参考サイト■
Raccoon's homepage Copyright
(C) 2000-2013 あらいベアー