[Rails→Vue]一対多の関係にある親子オブジェクトをネストさせた状態で取得する


[Vue→Rails]ネストされた状態の親子孫オブジェクト(一対多の関係あり)を全て同時にデータベースに保存するでは、Vue側で作ったネストされたデータを複数のテーブルに保存した。
この記事では、別々のテーブルに保存されたそれらのデータを再びネストされた形でVueコンポーネント側で取得する。

前提条件

モデル

親:School
子:Student

school.rb
# 親
class School
 has_many :students
student.rb
# 子
class Student
 belongs_to :school

保存されているレコード

School
{ id: 1, school_name: 'first' }
{ id: 2, school_name: 'second'}

Student
{ id: 1, student_name: 'Suzuki', age: 13, school_id: 1 }
{ id: 2, student_name: 'Hirano', age: 14, school_id: 1 }
{ id: 3, student_name: 'Nagai',  age: 15, school_id: 1 }
{ id: 4, student_name: 'Sato',   age: 13, school_id: 2 }
{ id: 5, student_name: 'Iguchi', age: 14, school_id: 2 }
{ id: 6, student_name: 'Arai',   age: 15, school_id: 2 }

axios.getによるデータの取得

$axiosはインスタンスプロパティに追加済み
schools#indexにgetリクエストを送りデータを取得する

<script>
...
  this.$axios.get('schools')
  .then(res => {
    console.log(res)
  })
  .catch(err => {
    console.log(err)
  })
...
</script>

コントローラ

to_jsonメソッドの使用

includeオプションでstudentsを指定する。school.studentsで取得されるstudentの配列をschoolにネストさせることができる。

schools_controller.rb
  def index
    schools = School.all
    string = schools.map.to_json(include: :students)

    render json: string
  end

取得できるデータ

to_jsonのincludeオプションで指定した'students'がそのままキー名になる。

data: [
   {
      schoolName: 'first',
      students: [  // studentsがそのままキー名になる
         { studentName: 'Suzuki', age: 13 },
         { studentName: 'Hirano', age: 14 },
         { studentName: 'Nagai',  age: 15 }
      ]
   },
   {
      schoolName: 'second',
      students: [
        { studentName: 'Sato',   age: 13 },
        { studentName: 'Iguchi', age: 14 },
        { studentName: 'Arai',   age: 15 }
      ]
   }
]

【追記】 キー名を変えたいとき

students以外のキー名にしたいとき(例:studentDataなど)
※キャメルケースの場合、一応Rubocopから怒られます

モデル

アソシエーションを取得するメソッドを親側に新しく定義し、目的のキー名をメソッド名にする。

school.rb
class School < ApplicationRecord
  has_many :students

  def studentData # 目的のキー名
    self.students
  end
end

コントローラ

to_jsonメソッドのmethodsオプションでそのメソッド名を指定する。
メソッド名がそのままキー名になる。

schools_controller.rb
  def index
    schools = School.all
    string = schools.map.to_json(methods: :studentData)

    render json: string
  end

取得できるデータ

data: [
   {
      schoolName: 'first',
      studentData: [ // studentDataがそのままキー名になる
         { studentName: 'Suzuki', age: 13 },
         { studentName: 'Hirano', age: 14 },
         { studentName: 'Nagai',  age: 15 }
      ]
   },
   {
      schoolName: 'second',
      studentData: [
        { studentName: 'Sato',   age: 13 },
        { studentName: 'Iguchi', age: 14 },
        { studentName: 'Arai',   age: 15 }
      ]
   }
]

参考文献