user_idメソッドを使用していないのにNoMethodError: undefined method `user_id`が出る
解決したいこと
2つのモデル(dictum_user と gogaku)を関連付けたテストをパスさせたい。
rails入門者です。railsチュートリアルを参考に現在アプリ開発をしていますが、2つのモデルの関連付ける作業で詰まってしまいました。
発生している問題・エラー
➜ dictum git:(connect_gogaku_and_d_user) ✗ rails t
Running via Spring preloader in process 18575
Run options: --seed 32489
# Running:
....E
Error:
GogakuTest#test_body_should_be_present:
NoMethodError: undefined method `user_id' for #<Gogaku id: nil, subject: "programing", body: " ", dictum_user_id: 762146111, created_at: nil, updated_at: nil>
test/models/gogaku_test.rb:32:in `block in <class:GogakuTest>'
rails test test/models/gogaku_test.rb:30
E
Error:
GogakuTest#test_subject_should_be_present:
NoMethodError: undefined method `user_id' for #<Gogaku id: nil, subject: " ", body: "ror", dictum_user_id: 762146111, created_at: nil, updated_at: nil>
test/models/gogaku_test.rb:27:in `block in <class:GogakuTest>'
rails test test/models/gogaku_test.rb:25
E
Error:
GogakuTest#test_user_id_should_be_present:
NoMethodError: undefined method `user_id' for #<Gogaku id: nil, subject: "programing", body: "ror", dictum_user_id: nil, created_at: nil, updated_at: nil>
test/models/gogaku_test.rb:22:in `block in <class:GogakuTest>'
rails test test/models/gogaku_test.rb:20
E
Error:
GogakuTest#test_micael_is_valid?:
NoMethodError: undefined method `user_id' for #<Gogaku id: nil, subject: "programing", body: "ror", dictum_user_id: 762146111, created_at: nil, updated_at: nil>
test/models/gogaku_test.rb:13:in `block in <class:GogakuTest>'
rails test test/models/gogaku_test.rb:12
E
Error:
GogakuTest#test_should_be_valid:
NoMethodError: undefined method `user_id' for #<Gogaku id: nil, subject: "programing", body: "ror", dictum_user_id: 762146111, created_at: nil, updated_at: nil>
test/models/gogaku_test.rb:17:in `block in <class:GogakuTest>'
rails test test/models/gogaku_test.rb:16
行ったテスト
# gogaku_test.rb
require 'test_helper'
class GogakuTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
def setup
@dictum_user = dictum_users(:michael)
@gogaku = @dictum_user.gogakus.build(subject:"programing", body:"ror")
end
test "micael is valid?" do
assert @dictum_user.valid?
end
test "should be valid" do
assert @gogaku.valid?
end
test "user id should be present" do
@gogaku.dictum_user_id = nil
assert_not @gogaku.valid?
end
test "subject should be present" do
@gogaku.subject = " "
assert_not @gogaku.valid?
end
test "body should be present" do
@gogaku.body = " "
assert_not @gogaku.valid?
end
end
test/fixtures/dictum_usres.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= DictumUser.digest('password') %>
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= DictumUser.digest('password') %>
マイグレーションファイル
# db/migrate/20220226234019_create_dictum_users.rb (その他
# add_column :dictum_users, :password_digest, :string ,add_index :dictum_users,
#:email, unique: true ,add_column :dictum_users,
#:password_digest, :stringを追加してあります。)
class CreateDictumUsers < ActiveRecord::Migration[6.0]
def change
create_table :dictum_users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
# db/migrate/20220301112520_create_gogakus.rb
class CreateGogakus < ActiveRecord::Migration[6.0]
def change
create_table :gogakus do |t|
t.string :subject
t.text :body
t.references :dictum_user, type: :bigint, foreign_key: true
t.timestamps
end
add_index :gogakus, [:dictum_user_id, :created_at]
# add_foreign_key :対象のテーブル名, :指定先のテーブル
end
end
コントローラー
# app/controllers/dictum_users_controller.rb
class DictumUsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def show
@dictum_user = DictumUser.find(params[:id])
end
def new
@dictum_user = DictumUser.new
end
def create
@dictum_user = DictumUser.new(dictum_user_params)
if @dictum_user.save
log_in @dictum_user
flash[:success] = "Welcome to the DICTUM!"
redirect_to @dictum_user
else
render "new"
end
end
def edit
@dictum_user = DictumUser.find(params[:id])
end
def update
@dictum_user = DictumUser.find(params[:id])
if @dictum_user.update(dictum_user_params)
flash[:success] = "Profile updated"
redirect_to @dictum_user
else
render 'edit'
end
end
def destroy
DictumUser.find(params[:id]).destroy
flash[:success] = "Dictum_user deleted"
redirect_to root_url
end
private
def dictum_user_params
params.require(:dictum_user).permit(:name, :email, :password,
:password_confirmation)
end
# beforeアクション
# ログイン済みユーザーかどうか確認
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# 正しいユーザーかどうか確認
def correct_user
@dictum_user = DictumUser.find(params[:id])
redirect_to(root_url) unless current_user?(@dictum_user)
end
# 管理者かどうか確認
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
# app/controllers/gogakus_controller.rb
class GogakusController < ApplicationController
before_action :set_gogaku, only:[:show,:edit,:update,:destroy]
def index
@gogakus = Gogaku.all
end
def show
# @gogaku = Gogaku.find(params[:id])
end
def new
@gogaku = Gogaku.new
end
def create
gogaku_params = params.require(:gogaku).permit(:subject,:body,:num)
@gogaku = Gogaku.new(gogaku_params)
if @gogaku.save
flash[:notice] = "教科書登録成功"
redirect_to gogakus_path
else
flash.now[:alert] = "登録失敗"
render :new
end
end
def edit
# @gogaku = Gogaku.find(params[:id])
end
def update
# @gogaku = Gogaku.find(params[:id])
gogaku_params = params.require(:gogaku).permit(:subject, :body ,:num)
if @gogaku.update(gogaku_params)
flash[:notice]="更新成功"
redirect_to gogakus_path
else
flash.now[:alert]="更新失敗"
render:edit
end
end
def destroy
# @gogaku = Gogaku.find(params[:id])
@gogaku.destroy
flash[:notice]="削除しました"
redirect_to gogakus_path
end
private
def set_gogaku
@gogaku ||= Gogaku.find(params[:id])
end
end
自分で試したことなど
・まず2つのモデルが正しく関連付けできているかだが、エラー文にdictum_user_id: 762146111とあるので関連付けはできているのではと考えた。(その前に親よりも先に子を作ってしまったのでエラーが出ていたが、タイムスタンプを書き換えてエラーを解決)
・エラー文ではuser_idという定義されていないメソッドがGogakuに対して呼び出されているとあるが、user_idメソッドは使用していない。test_helperには
# テストユーザーがログイン中の場合にtrueを返す
def is_logged_in?
!session[:user_id].nil?
end
# テストユーザーとしてログインする
def log_in_as(user)
session[:user_id] = user.id
end
end
class ActionDispatch::IntegrationTest
# テストユーザーとしてログインする
def log_in_as(user, password: 'password', remember_me: '1')
post login_path, params: { session: { email: user.email,
password: password,
remember_me: remember_me } }
end
のように記述しているがsessionで使ったコードなので関係ないはず。消したらテストのエラーが追加で増えただけだった。
・新しくインスタンスを作ったのに、id, created_at, updated_atがnilになってしまっているのが気になる。
・has_many belongs_toは記述済み
・rails入門者のため何かしら間違った認識をしているかもしれません。何かしらアドバイスがあればよろしくお願い致します。
0