railsでアルバム管理機能を実装

前回の記事 railsで写真アップロード機能を実装 - watariseinの日記の続き。

投稿した写真群とアルバムを多対一で管理できるようにします。

1. 参照先の外部キーを追加する

まず、多側のテーブル(前回作成したpicturesテーブル)にxxx_idという名で外部キーを追加します。 xxxの箇所は参照先のモデル名にする必要があります。 今回の場合は、Albumモデルを参照するため、album_idにする必要があります。

Albumモデルとalbumsテーブルの作成をします。

$ rails g model Album name:string
$ rake db:migrate

album_idを外部キーとしてpictureテーブルに追加するマイグレーションファイルを作成します。

$ rails g migration add_album_id_to_pictures album_id:integer
$ rake db:migrate

ちなみに、新規にPictureモデルを作成する場合は以下の手順で作成します。

$ rails g model Pcture album_id:integer date:date
$ rake db:migrate

2. モデルファイルに1対多関連の宣言を追加

モデルにhas_manyとbelongs_toを追加する

「1側」のAlbumにhas_manyを追加します。 "Album has_many pictures"と読めば、「Albumは複数のPictureを持つ」となります。 また、dependent: :destroyオプションを追加することで、albumレコードをdestoryメソッドで削除したら、Railsがそのalbumに紐づいていたpictureを全て削除してくれます。

「多」側の編集

$ vi app/models/album.rb
class Album < ActiveRecord::Base
  has_many :pictures, dependent: :destroy
end

has_manyメソッドには次のようなオプションを指定できます。

class_nameオプションで関連するモデルのクラス名を指定でき、関連名と参照先のクラス名を異なるものにできる。 foreign_keyオプションで参照先を参照する外部キーの名前を指定できる。デフォルトは、参照先のモデル名_id dependentオプションで親オブジェクトが削除された時の扱いを指定できる。destroyとdelete_allなどが指定可能。 asオプションでポリモフィック関連を定義できる。 throughオプションでモデル接続の関連を設定できる。 など

「多側」にbelongs_toメソッドを記載します。 "Picture belogns_to album"と読めば、「Pictureは1つのAlbumに属する」となります。

$ app/models/picture.rb
class Picture < ActiveRecord::Base
  belongs_to :album
end

belogns_toメソッドには次のようなオプションを指定できます。

class_nameオプションで関連するモデルのクラス名を指定でき、関連名と参照先のクラス名を異なるものにできできる。 foreign_keyオプションで参照先を参照する外部キーの名前を指定できる。デフォルトは、参照先のモデル名_id dependentオプションで親オブジェクトが削除された時の扱いを指定できる。destroyとdeleteが指定可能。 polymorphicオプションでポリモフィック関連を定義できる。 など

例えば、デフォルトのpicture.albumではなく、picture.photo_bookでアクセス可能にする

# app/models/order.rb 多側
class Picture < ActiveRecord::Base
  belongs_to :photo_book, class_name: "Album", foreign_key: "album_id"
end

4. 使えるようになるメソッド

これらを追加することで自動的に次のようなメソッドが使えるようになります。

# 作成
album = Album.create(name: "あるばむ1") # albumを作成し、DBに保存
picture1 = album.pictures.build(date: Time.now) # picture1を作成(newの代わりにbuildを使う)
picture1.save # picture1をDBに保存
picture2 = album.pictures.create(date: Time.now) # picture2を作成し、保存

# リレーション
album.pictures         # => pictureオブジェクトの配列
album.pictures.exists? # => true (存在するか判定する)
album.pictures.empty?  # => false (空か判定する)
picture1.album     # => albumオブジェクト(pictureを所持しているalbum)

# album.pictures内のレコードのみから検索ができる
album.pictures.find(...)
album.pictures.find_by(...)
album.pictures.where(...)

# 削除
album.count # => 2
album.destory # => dependent: :destroyが指定されているので、pictureも削除される
album.count # => 0

これで、アルバムと写真の多対一構成の構築が完了した。 次回は写真を複数登録できるようビューなども作成する