Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Ruby on Rails で多対多のモデルを構築した場合にハマったエラー

More than 3 years have passed since last update.

はじめに

参考書やネットの情報を参考に多対多のモデルを構築した所、謎のエラーに遭遇し、なかなか解決できなかったので、ここに情報を残しておきます。

簡単にいうと、UserとProjectモデル + 多対多実現用のUserProjectテーブルでデータのやり取りをしようとしていたのですが、以下のエラーに阻まれましたので、その解決法です。

ActiveRecord::UnknownAttributeError: unknown attribute 'user_id' for UserProject.

環境

・Mac OS X EI Capitan (10.11.5)
・Ruby 2.3.0
・Rails 4.2.6

エラーのはじまり

Model

以下の多対多のモデルを構築しました
・User
・Project
多対多のモデルを実現するために、以下の中間テーブルも構築しました
・UserProject

モデル生成

ユーザー情報を持ったUserモデルと、簡単なプロジェクト情報を持ったProjectモデルを生成し、データベースを構築します。

$ rails g model User name email password_diggest
$ rails g model Project name body:text
$ rails g model UserProject User:reference Project:reference
$ rake db:migrate

ここまでは、全く問題なしです。
多対多の場合、user_project.rbbelongs_to が自動的に明記されますが、has_many は手動で書かないといけないみたいなので、それぞれのモデルに追記します。

user.rb
class User < ActiveRecord::Base
    # DB relations
    has_many :UserProject  # 追記
    has_many :Project, through: :UserProject  # 追記
end
project.rb
class Project < ActiveRecord::Base
    # DB relations
    has_many :UserProject  # 追記
    has_many :User, through: :UserProject  # 追記
end

追記していませんが、一応、中間テーブルはこちら

user_project.rb
class UserProject < ActiveRecord::Base
  belongs_to :User
  belongs_to :Project
end

中間テーブルに情報がわたらない

アプリケーションを作っている途中で、保存したProjectの情報がユーザーと結びついていないことに気付く。
ちなみに、ProjectのControllerは以下の通り。

projects_controller.rb
class ProjectsController < ApplicationController
  def new
    @project = Project.new()
  end

  def create
    # セッションで管理しており、current_userでログイン中のユーザーを管理
    @user = current_user
    # ログイン中のユーザーにプロジェクト情報を追加
    @project = @user.Project.new(params_project)
    if @project.save
      # DB保存成功時の処理
    else
      # DB保存失敗時の処理
    end
  end

  private

  def params_project
    params.require(:project).permit(:name, :body)
  end
end

コンソールで確認

とりあえず、railsのコンソールで確認してみる
※ pry をインストールしていない人は 補足:pryのインストール を参照

まず、railsのコンソールを立ち上げる

$ rails c

モデル間でが正しく参照しているか確認する。

[1] pry(main)> show-models
Project
  id: integer
  name: string
  body: text
  created_at: datetime
  updated_at: datetime
  has_many :User (through :UserProject)
  has_many :UserProject (foreign_key :Project_id)
User
  id: integer
  name: string
  email: string
  password_digest: string
  created_at: datetime
  updated_at: datetime
  has_many :Project (through :UserProject)
  has_many :UserProject (foreign_key :User_id)
UserProject
  id: integer
  User_id: integer
  Project_id: integer
  created_at: datetime
  updated_at: datetime
  belongs_to :Project
  belongs_to :User

うん。悪くない。
というわけで、適当にユーザーを作って、そこに、プロジェクトを紐付けてみる。

user = User.create(name: "user1")
project = Project.create(name: "project1")
user.Project << project

ここで、DBへの書き込みが失敗し、以下のエラーに遭遇

ActiveRecord::UnknownAttributeError: unknown attribute 'user_id' for UserProject.

user_id という未定義のパラメータが渡っているようですね。
あれ? User_id が渡って欲しいんだけど。。。
ここから、色々と試行錯誤して時間を費やしましたが、結果的には、非常に簡単に解決したので、ご安心ください。

エラー対処

結論からいうと、中間テーブルが参照する際の外部キーを変更してやらないとだめみたいでした。
というわけで、それぞれのモデルに外部キーを明記しました。

user.rb
class User < ActiveRecord::Base
    # DB relations
    has_many :UserProject, foreign_key: 'User_id'  # foreign_keyを追記
    has_many :Project, through: :UserProject
end
project.rb
class Project < ActiveRecord::Base
    # DB relations
    has_many :UserProject, foreign_key: 'Project_id' # foreign_keyを追記
    has_many :User, through: :UserProject
end

これで無事解決しました。

補足

pryのインストール

rails のコンソールで、いろいろと綺麗に表示できる優れものの pry をインストールします。

以下をGemfileに追記する

Gemfile
gem 'pry-rails'
gem 'pry-doc'

あとは、インストールするだけ

$ bundle install

いつもどおり、rails のコンソールを立ち上げると、pryが適用されています。

$ rails c
[1] pry(main)>
yoshizaki_91
株式会社キカガク代表取締役の吉崎です。 人工知能・機械学習を初学者向けに無料で学べる『脱ブラックボックスコース』を提供しています。
https://www.kikagaku.ai
kikagaku
教育の力で社会により良い変革を与えるため、AIを始めとする先端技術に関する教育とコンサルティングを行っています。
https://www.kikagaku.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away