テーブルの関連
SKIPのユーザーのデータには、SNSらしく足跡やプロフィールなどが付随しています。これらの足跡やプロフィールの情報は、ユーザーと同じUsersテーブルに保存されているわけではなく、それぞれ別のテーブルで管理されています。
テーブル同士は、外部キーを持たせることで関連付けています。Usersテーブルの1行に対して、足跡テーブルにはほかのユーザーがアクセスした履歴という形で複数のレコードが残るため、ユーザーと足跡は、1対多の関係になっているといえます。
このようなテーブル同士の関連も、ActiveRecordでは非常にシンプルに定義することができるようになっています。
Userモデルを見てみましょう。
27 |
has_many :tracks, :order => "updated_on DESC", :dependent => :destroy' |
app/models/user.rb |
足跡のデータはTracksテーブルに保存され、それを扱うためのActiveRecordのクラスがTrackモデルになります。ユーザー1人に対して複数の足跡があるので、Tracksテーブルのレコードには、誰にとっての足跡かを示すためのuser_idというカラムを持たせています。こうしたデータ構造になっているのであれば、has_manyメソッドを用いて1対多の関連をRubyで表現することができます。
トランザクション
ActiveRecordでのトランザクション処理の説明のために、SKIPの管理機能にあるユーザー情報のCSVアップロード機能のソースコードを読んでいくことにします。CSVアップロード機能は、CSVファイルに用意したデータを読み込み、一度に多数のユーザーの初期登録を実施するために使われます。
そこで、「複数のレコードを一度に登録したり、1件でも失敗したりした場合はすべてやり直し」ということで、トランザクション機能を利用しています。
図5 CSVアップロード機能 |
それではコードを見ていきましょう。
137 |
def import |
app/controllers/admin/users_controller.rb |
137行目から始まるimportメソッドが、WebブラウザからポストされたCSVデータをデータベースに登録するアクションです。
このimportメソッドのポイント部分は、144行目と145行目の処理になります。そこまでは、必要な変数の準備と入力形式のチェックを行っているにすぎません。
144行目で、Userモデルのmake_usersメソッドを用いて、送られてきたファイルからUserモデルの配列を構築して取得しています。このmake_usersメソッドの内部では、CSVファイルの解析を行い、そのデータを基に、すでに登録済みのユーザーが見つかればそのオブジェクトを、見つからなければ新規のオブジェクトとして、配列を構築しています。
そして、そのUserモデルオブジェクトの配列を145行目で、引数として渡してimport!メソッドを呼び出しています。このimport!メソッドの中でトランザクションを利用しています。では、privateメソッドであるimport!メソッドの中身を見ることにします。
247 |
def import!(users, rollback = true) |
トランザクション処理を開始するには、ActiveRecordで用意されたtransactionメソッドを使います。248行目のように、Rubyのブロックの形でトランザクション処理を記述します。
249行目から256行目の間に、処理に失敗して例外が発生すると、ロールバック処理が実行され、ブロック内のそれまでの処理がなかったことになります。
250行目、252行目で、save!メソッドを呼んでいます。前述したとおり、この!マークの付いたメソッドは、バリデーションなどの失敗時には例外を発生させるため、トランザクション処理内で使う場合は、必ず!マークの付いたsave!を呼ぶようにします。transactionブロックを抜けるタイミングで、コミット処理が実行されるようになっています。
今回は、ActiveRecordの機能を中心に、モデルの使い方などを解説してきました。ActiveRecordに備わっている基本的な機能と、便利に使えそうだという可能性は感じてもらえたのではないでしょうか。
今回紹介した機能は、まだまだActiveRecordのほんの入り口の一部にすぎません。また、SKIPで使っている実際のソースコードということもあり、一般的によく使われるRailsバージョン1系から存在している機能の説明に終始しました。Railsバージョン2系で拡張された、named_scopeや、dirtyオブジェクトなどの便利で面白い機能については、ぜひとも学んでみてください。
次回は、MVCのうちのビュー(V)の部分を中心に、AjaxのRailsアプリケーションでの実装などを解説する予定です。
4/4 |
Index | |
ActiveRecordを使ったソースコードを読もう | |
Page1 SKIPバージョン1.0リリース! MVCモデルのM |
|
Page2 データの検索 データの更新 |
|
Page3 値の検証(バリデーション) コールバック |
|
Page4 テーブルの関連 トランザクション |
Railsコードリーディング 〜scaffoldのその先へ〜 |
Ruby/Rails関連記事 |
プログラミングは人生だ まつもと ゆきひろのコーディング天国 ときにプログラミングはスポーツであり、ときにプログラミングは創造である。楽しいプログラミングは人生をより実りあるものにしてくれる |
|
生産性を向上させるRuby向け統合開発環境カタログ Ruby on Rails 2.0も強力サポート 生産性が高いと評判のプログラミング言語「Ruby」。統合開発環境を整えることで、さらに効率的なプログラミングが可能になる |
|
かんたんAjax開発をするためのRailsの基礎知識 Ruby on RailsのRJSでかんたんAjax開発(前編) 実はAjaxアプリケーション開発はあなたが思うよりも簡単です。まずはRuby on Railsの基礎知識から学びましょう |
|
Praggerとnetpbmで作る画像→AA変換ツール Rubyを使って何か面白いものを作ってみよう! 一般的な画像をアスキーアートに変換するツールを作ってみる。さらに出力にバリエーションを持たせてみよう |
|
コードリーディングを始めよう Railsコードリーディング〜scaffoldのその先へ〜(1) 優れたプログラマはコードを書くのと同じくらい、読みこなす。優れたコードを読むことで自身のスキルも上達するのだ |
|
- プログラムの実行はどのようにして行われるのか、Linuxカーネルのコードから探る (2017/7/20)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。最終回は、Linuxカーネルの中では、プログラムの起動時にはどのような処理が行われているのかを探る - エンジニアならC言語プログラムの終わりに呼び出されるexit()の中身分かってますよね? (2017/7/13)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、プログラムの終わりに呼び出されるexit()の中身を探る - VBAにおけるFileDialog操作の基本&ドライブの空き容量、ファイルのサイズやタイムスタンプの取得方法 (2017/7/10)
指定したドライブの空き容量、ファイルのタイムスタンプや属性を取得する方法、FileDialog/エクスプローラー操作の基本を紹介します - さらば残業! 面倒くさいエクセル業務を楽にする「Excel VBA」とは (2017/7/6)
日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。本稿では、業務で使うことが多い「Microsoft Excel」で使えるVBAを紹介する。※ショートカットキー、アクセスキーの解説あり
|
|