遠隔テーブルとアクティブレコードの関連付け

17101 ワード

アクティブなレコードでは、データベースのテーブルを一緒にアクティブなレコード協会を介して接続することができます、簡単に私たちのデータベースで動作するように.下の図を考えます.

これらのテーブルの間に別の関連付けを作成することにより、アクティブなレコードは私たちのモデルを追加のメソッドにアクセスできるようになります.最後に、私のようなテーブルと対話できます.
playlist = Playlist.first

p playlist.name # => "Very Best of the 90's"
p playlist.tracks.sample.name # => "Step By Step"
p playlist.albums.sample.name # => "Siamese Dream"
p playlist.artists.sample.name # => "Alanis Morissette"

p playlist.albums.sample
          .tracks.first
          .playlists.sample
          .artists.first.name # => "Fleetwood Mac"

セットアップ


この記事をできるだけ短くすることに興味があるので、Active Recordを設定する方法や、最初のデータベーステーブルとテーブルモデルを作成する方法はありません.起動するには、次のようなデータベーススキーマがあります.
# db/schema.rb

# ...

  create_table "albums", force: :cascade do |t|
    t.string "name"
    t.datetime "release_data"
    t.string "img_url"
  end

  create_table "artists", force: :cascade do |t|
    t.string "name"
    t.integer "popularity"
    t.string "img_url"
  end

  create_table "playlists", force: :cascade do |t|
    t.string "name"
    t.string "img_url"
  end

  create_table "tracks", force: :cascade do |t|
    t.string "name"
    t.integer "duration_s"
  end

関連付けの設定


この記事の冒頭の図に注意してください.“プレイリスト”テーブルと“アーティスト”テーブルはどこ近くに近接していないが、アクティブなレコード協会を使用して、我々は直接呼び出すだけで特定のプレイリストで表されるすべてのアーティストにアクセスすることができます.artists のインスタンスPlaylist .
playlist = Playlist.first
artist = Artist.first

p playlist.artists.pluck(:name).uniq
  # =>  ["Post Malone", "Kid Cudi", "Mr. Probz", "Miley Cyrus",
  #       "Fleetwood Mac","The xx", "Elton John", "Wiz Khalifa"]

# It works both ways
p artist.playlists.pluck(:name)
  # => ["Oldies", "Classic Hits"]


唐辛子の簡単説明

#pluck アクティブレコードで提供される非常に便利なメソッドです.レコードのコレクションに呼び出されたときに値の配列を返します.apidock.com これは言う#pluck :

"Use #pluck as a shortcut to select one or more attributes without loading a bunch of records just to grab the attributes you want."


私はプレイリスト、アルバム、アーティスト、&トラックの表を表す4つのモデル(これまで)を作成しました.

さて、各モデルのテーブルアソシエーションを作成します.データベースのダイアグラムをもう一度見てみましょう.

それを通して考えると、それぞれのアーティストが多くのアルバムを持っていると言うのは妥当でしょう.だから私たちのアーティストモデルの中で、我々はhas_many マクロはそうです:
# app/models/artist.rb
class Artist < ActiveRecord::Base
  has_many :albums # <- plural
end
そして、アルバムモデルの中で、Abelongs_to マクロ
# app/models/album.rb
class Album < ActiveRecord::Base
  belongs_to :artist # <- singular
end
注意-連想を作成するときにテーブル名の正しい単数形/複数形を使用するようにしてください.
続けて、各アルバムは、多くのトラックを持っており、各トラックは1つのアルバム(私たちの場合)に属しています.我々のアルバムモデルを加えること:
# app/models/album.rb
class Album < ActiveRecord::Base
  belongs_to :artist
  has_many :tracks
end
そして、トラックモデルの中で:
class Track < ActiveRecord::Base
  belongs_to :album
end
さらに進む前に、私たちが今までに何をしているかチェックしたい.しかし、最初に、私は新しい移行をつくることによって、私のアルバムとトラックモデルに外国のキーを加える必要があります.
#db/migrate/20220402193754_add_foreign_keys_to_albums_and_tracks.rb
class AddForeignKeysToAlbumsAndTracks < ActiveRecord::Migration[6.1]
  def change
    add_column :albums, :artist_id, :integer
    add_column :tracks, :album_id, :integer
  end
end
今、私はすべてのアーティストのトラックを呼び出すことで取得することができます:
Track.joins(album: [:artist]).where(:artist => {:name => "Nine Inch Nails"})`
  # returns an array of all tracks by "Nine Inch Nails"
注意#joins & #where データベースを問い合わせるために、アクティブレコードによって提供されるFinderメソッドです.あなたは彼らについてもっと学ぶことができますhere .
すべては良いです、これまで、続きましょう.
我々の最後の直接協会は、前の2とは異なります.続けて考えると、各プレイリストは多くのトラックを持っていますが、各トラックにも多くのプレイリストを持つことができます.この関係を表現するために、私たちはトラックテーブル&プレイリストテーブルを一緒にする新しいテーブルを作成する必要があります.

結合テーブルの作成


新しい移行ファイルでは、次のようにします.
class CreatePlaylistTracksTable < ActiveRecord::Migration[6.1]
  def change
    create_table :playlist_tracks do |t|
      t.integer :playlist_id
      t.integer :tracks_id
    end
  end
end
これは多くの多くの関係で一緒に私たちのトラック&プレイリストテーブルをリンクする結合テーブルを作成します.次に、このテーブルの新しいモデルを作成する必要があります.
class PlaylistTrack < ActiveRecord::Base
  belongs_to :playlist
  belongs_to :track
end
これで、私のデータベース全体が接続されます.私は今のようにクエリを作成するためのチェーンメソッドを一緒にすることができます.
artists = Artists.joins(album: [tracks: [:playlists]])
                 .where(:playlist => {:name => "Very Best of the 90's"})
それは私にプレイリストで表されるアーティストのリストを与える必要があります“90年代の最高のベスト”.
データベースから必要なデータを取得できるようになりました.しかし、上記の質問はちょっと醜いです.次のように書きます.
artists = Playlist.find_by(name: "Very Best of the 90's").artists
この呼び出しを行うことができるように、私はいくつかの関連付けを設定する必要があります.

アソシエーションのラッピング


データベースのクエリを過充電するために、私のモデルにいくつかの関連付けを追加しました.
# app/models/playlist.rb
class Playlist < ActiveRecord::Base
  has_many :playlist_tracks
  has_many :tracks, through: :playlist_tracks
  has_many :albums, through: :tracks
  has_many :artists, through: :albums
end

# app/models/track.rb
class Track < ActiveRecord::Base
  belongs_to :album
  has_one :artist, through: :album
  has_many :playlist_tracks
  has_many :playlists, through: :playlist_tracks
end

# app/models/album.rb
class Album < ActiveRecord::Base
  belongs_to :artist
  has_many :tracks
  has_many :playlists, through: :tracks
end

# app/models/artist.rb
class Artist < ActiveRecord::Base
  has_many :albums
  has_many :tracks, through: :albums
  has_many :playlists, through: :tracks
end
この設定により、以下のようなスーパー簡単なクエリを作成できます.
artists = Playlist.find(10).artists.pluck(:name).uniq
これは、プレイリスト内のすべてのアーティストのリストを返します.それはかなりクールです.

結論


そしてそれです.現在、私の質問は過充電されます、そして、私は複雑な質問を微風にするためにこのセットアップで働く方法を書くことができます.
読書ありがとう!