Railsで多対多のモデル

去年からずーっとこの課題でひっ掛かっている。

Mail -> MailUser <- Userのモデルを考えてみる。
スキーマは以下

  create_table "mail_users", :force => true do |t|
    t.boolean  "active"
    t.integer  "user_id"
    t.integer  "mail_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "mails", :force => true do |t|
    t.string   "title"
    t.text     "comment"
    t.date     "write_date"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "users", :force => true do |t|
    t.string   "name"
    t.string   "email"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

modelは以下

class Mail < ActiveRecord::Base
  # has_many for user through mail_user
  has_many :mail_user 
  has_many :user, :through=>:mail_user
  # nested attribute
  accepts_nested_attributes_for :mail_user
end

class User < ActiveRecord::Base
  # has_many for user through mail_user
  has_many :mail_user 
  has_many :mail, :through=>:mail_user
  # nested attribute
  accepts_nested_attributes_for :mail_user
end

class MailUser < ActiveRecord::Base
  belongs_to :mail
  belongs_to :user
end

それぞれをscaffoldで作成してmigrateでDBを作成して、テスト用のデータを登録して。

さて、MailのShow画面で、関連するユーザ名を表示する画面に挑戦。
まずは、Show画面でMailUserのindex画面を表示する事から。
partialを使うので、view/mail/show.html.erbを

<p>
  <b>Title:</b>
  <%=h @mail.title %>
</p>
<p>
  <b>Comment:</b>
  <%=h @mail.comment %>
</p>
<p>
  <b>Write date:</b>
  <%=h @mail.write_date %>
</p>
ここから
<div id="mail_users">
  <%= render :partial=>"mail_user_index", :locals=>{:mail_users=>@mail.mail_user} %>
</div>
ここまでを追加
<%= link_to 'Edit', edit_mail_path(@mail) %> |
<%= link_to 'Back', mails_path %>

と修正して
view/mail_user/index.html.erbをview/mail/_mail_user_index.html.erbにコピーして

<h1>Listing mail_users</h1>
<table>
  <tr>
    <th>Active</th>
    <th>User</th>
    <th>Mail</th>
  </tr>
<% mail_users.each do |mail_user| %>  @mail_usersをmail_usersに変更
  <tr>
    <td><%=h mail_user.active %></td>
    <td><%=h mail_user.user_id %></td>
    <td><%=h mail_user.mail_id %></td>
    <td><%= link_to 'Show', mail_user %></td>
    <td><%= link_to 'Edit', edit_mail_user_path(mail_user) %></td>
    <td><%= link_to 'Destroy', mail_user, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>
<br />
<%= link_to 'New mail_user', new_mail_user_path %>

このままでは、User_IDとMail_IDを表示する事は出来ても、ユーザ名が表示できないので、以下のように修正

<table>
  <tr>
    <th>Active</th>
    <th>User Name</th>
    <th>     Address</th>
  </tr>
<% mail_users.each do |mail_user| %>  @mail_usersをmail_usersに変更
  <tr>
    <td><%=h mail_user.active %></td>
    <td><%=h mail_user.user.name %></td>   <- belongs_to でuserと連携できる
    <td><%=h mail_user.user.email %></td>     <- のでuser.nameとuser.emailを参照
    <td><%= link_to 'Show', mail_user %></td>
    <td><%= link_to 'Edit', edit_mail_user_path(mail_user) %></td>
    <td><%= link_to 'Destroy', mail_user, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>