2012年10月4日木曜日

Railsで1対多の関係を設定するサンプル

Rails の場合はSQLを直接使わないので、下図のような1対多の関係を設定するにはどうすれば良いのだろうか?


まずはRails付属のSQLiteのSQLでやってみる。

▽テーブルの作成
E:\Sites\mytest\db>sqlite3 development.sqlite3
SQLite version 3.7.3
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table team(id, name);
sqlite> create table member(id, team_id, name);
sqlite> insert into team values(1, 'team1');
sqlite> insert into member values(1, 1, 'member1');
sqlite> insert into member values(2, 1, 'member2');
▽データの取得
sqlite> select team.id, team.name, member.id, member.name from team, member wher
e team.id = member.team_id;
1|team1|1|member1
1|team1|2|member2
こんな感じで、簡単にできる。(外部キーは未設定。)

Rails の ActiveRecord では、references という型を指定することで、他のクラスへの外部参照を設定できるようである。

まずは sacffold を作成してみる。

先程作成したテーブルと同じ名前のテーブルは作成できないので、rteam と rmember で作成する。(長いので実行結果は省略。)
rails g scaffold rteam name:string
rails g scaffold rmember name:string rteam:references
Rmember のクラスには、"belongs_to :rteam" という属性が追加されている。
class Rmember < ActiveRecord::Base
  belongs_to :rteam
end
Rmember のクラスは何も変更されていない。
"has_many :rmember" を手動で追加する必要があるようだ。

▽修正前
class Rteam < ActiveRecord::Base
end
▽修正後
class Rteam < ActiveRecord::Base
   has_many :rmembers
end
修正後にデータベースの Migration を実行。
E:\Sites\mytest>rake db:migrate
==  AddThirdnameOnecolumnmodel: migrating =====================================
-- add_column(:onecolumnmodels, :thirdname, :string)
   -> 0.0020s
==  AddThirdnameOnecolumnmodel: migrated (0.0020s) ============================

==  CreateRteams: migrating ===================================================
-- create_table(:rteams)
   -> 0.1510s
==  CreateRteams: migrated (0.1520s) ==========================================

==  CreateRmembers: migrating =================================================
-- create_table(:rmembers)
   -> 0.0020s
-- add_index(:rmembers, :rteam_id)
   -> 0.0350s
==  CreateRmembers: migrated (0.0390s) ========================================
db/schema.rb を見ると、rteam_id が rmembers テーブルに追加されている。
index も追加されているようだ。
  create_table "rmembers", :force => true do |t|
    t.string   "name"
    t.integer  "rteam_id"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  add_index "rmembers", ["rteam_id"], :name => "index_rmembers_on_rteam_id"

  create_table "rteams", :force => true do |t|
    t.string   "name"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end
自動生成されたテストデータを読み込でおく。
E:\Sites\mytest>rake db:fixtures:load

rails consoleから、Rteamクラスのデータを確認してみる。
現時点では、Rteam に関連付けられた Rmember は空の状態。
E:\Sites\mytest>rails console
Loading development environment (Rails 3.2.1)
irb(main):001:0> rteam1=Rteam.find(980190962)
=> #<Rteam id: 980190962, name: "MyString", created_at: "2012-10-02 04:13:28", u
pdated_at: "2012-10-02 04:13:28">
irb(main):002:0> rteam1.rmembers
=> []
rmembers の配列に Rmember から値を抽出して追加。
irb(main):003:0> rteam1.rmembers << Rmember.find(980190962)
=> [#<Rmember id: 980190962, name: "MyString", rteam_id: 980190962, created_at:
"2012-10-02 04:13:28", updated_at: "2012-10-02 05:52:04">]
Rmember 側の rteam_id も自動で追加された。
irb(main):005:0> rteam1.rmembers
=> [#<Rmember id: 980190962, name: "MyString", rteam_id: 980190962, created_at:
"2012-10-02 04:13:28", updated_at: "2012-10-02 05:52:04">]

0 件のコメント:

コメントを投稿