2012年10月7日日曜日

Railsで1対多の関係を設定するサンプル~既存モデルの修正

以前の記事では、RteamクラスとRmemberクラスに1対多の関係を設定した。

今回は、Rteamのクラスの上位にRleagueというクラスを作成して、さらに1対多の関係を設定してみたい。


以前の記事の場合と異なり、外部クラスへの参照を最初から維持するクラスを新規に作成するわけではなく、既存のクラスに後から追加することになる。

まずは Rleagueクラスの scaffoldを作成する。(実行結果は省略。)
rails g scaffold rleague name:string
次に、Rteamクラスに Rleagueクラスへの参照を追加するための migarationファイルの generateを行う。
E:\Sites\mytest>rails g migration add_rleagueref_rteammodell
      invoke  active_record
      create    db/migrate/20121005010409_add_rleagueref_rteammodell.rb
作成された migarationファイルに、Rleagueへのreferenceのカラムを追加する。
class AddRleaguerefRteammodell < ActiveRecord::Migration
  def up
    add_column :rteams, :rleague, :reference
  end

  def down
    remove_column  :rteams, :rleague
  end
end
migration を実行する。
E:\Sites\mytest>rake db:migrate
==  AddRleaguerefRteammodell: migrating =======================================
-- add_column(:rteams, :rleague, :reference)
   -> 0.0010s
==  AddRleaguerefRteammodell: migrated (0.0030s) ==============================

==  CreateRleagues: migrating =================================================
-- create_table(:rleagues)
   -> 0.1100s
==  CreateRleagues: migrated (0.1100s) ========================================
しかしながら、db/schema.rb を確認すると、rteamsテーブルにはエラーが発生している。
"reference" という型は後付けでは追加できないようだ。

"reference" 型を利用する代わりに、参照先のクラスのIDをクラス内に保持することになるらしい。

そこで、RleagueクラスのIDのカラムを追加するために、migrationファイルの generateを再度実行する。 (実行結果は省略。)
rails g migration add_rleagueid_rteammodel
作成された migarationファイルに、rleague_id というカラムを追加する。
class AddRleagueidRteammodel < ActiveRecord::Migration
  def up
    add_column :rteams, :rleague_id, :integer
    add_index :rteams, :rleague_id
  end

  def down
    remove_index :rteams, :rleague_id
    remove_column :rteams, :rleague_id
  end
end
以前の記事でも、"reference" 型を指定して作成されたテーブルには、rteam_id という名前でinteger型のカラムが追加されていたので、"reference" 型というのは実体のある型ではなく、単なるシンタックスシュガーなのかもしれない。

migrartionを再度実行する。
E:\Sites\mytest>rake db:migrate
==  AddRleagueidRteammodel: migrating =========================================
-- add_column(:rteams, :rleague_id, :integer)
   -> 0.0020s
-- add_index(:rteams, :rleague_id)
   -> 0.0280s
==  AddRleagueidRteammodel: migrated (0.0320s) ================================
今回は問題なく作成できたようだ。

Rleagueクラスの has_many :rteams と Rteamクラスの belongs_to :rleague は手動で追加する。
class Rleague < ActiveRecord::Base
  has_many :rteams
end

class Rteam < ActiveRecord::Base
  has_many :rmembers
  belongs_to :rleague
end
これで model側の修正は完了。
view側も修正しておく。

▽変更後の_form.html.erb
<%= form_for(@rteam) do |f| %>
  <% if @rteam.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@rteam.errors.count, "error") %> prohibited this rteam from being saved:</h2>

      <ul>
      <% @rteam.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :rleague %><br />
    <%= f.collection_select(:rleague_id, Rleague.find(:all), :id, :name) %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
▽editの実行結果



▽変更後のshow.html.erb
<p id="notice"><%= notice %></p>

<p>
  <b>Name:</b>
  <%= @rteam.name %>
</p>

<p>
  <b>Member's name:</b><br />
  <% @rteam.rmembers.each do |rmember| %>
    <%= rmember.name %><br />
  <% end %>
</p>

<p>
  <b>League:</b>
  <%= @rteam.rleague.name %>
</p>

<%= link_to 'Edit', edit_rteam_path(@rteam) %> |
<%= link_to 'Back', rteams_path %>
▽showの実行結果


0 件のコメント:

コメントを投稿