#はじめに
参考書やネットの情報を参考に多対多のモデルを構築した所、謎のエラーに遭遇し、なかなか解決できなかったので、ここに情報を残しておきます。
簡単にいうと、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.rb
に belongs_to
が自動的に明記されますが、has_many
は手動で書かないといけないみたいなので、それぞれのモデルに追記します。
class User < ActiveRecord::Base
# DB relations
has_many :UserProject # 追記
has_many :Project, through: :UserProject # 追記
end
class Project < ActiveRecord::Base
# DB relations
has_many :UserProject # 追記
has_many :User, through: :UserProject # 追記
end
追記していませんが、一応、中間テーブルはこちら
class UserProject < ActiveRecord::Base
belongs_to :User
belongs_to :Project
end
##中間テーブルに情報がわたらない
アプリケーションを作っている途中で、保存したProjectの情報がユーザーと結びついていないことに気付く。
ちなみに、ProjectのControllerは以下の通り。
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 が渡って欲しいんだけど。。。
ここから、色々と試行錯誤して時間を費やしましたが、結果的には、非常に簡単に解決したので、ご安心ください。
#エラー対処
結論からいうと、中間テーブルが参照する際の外部キーを変更してやらないとだめみたいでした。
というわけで、それぞれのモデルに外部キーを明記しました。
class User < ActiveRecord::Base
# DB relations
has_many :UserProject, foreign_key: 'User_id' # foreign_keyを追記
has_many :Project, through: :UserProject
end
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に追記する
gem 'pry-rails'
gem 'pry-doc'
あとは、インストールするだけ
$ bundle install
いつもどおり、rails のコンソールを立ち上げると、pryが適用されています。
$ rails c
[1] pry(main)>