I am facing a very strange problem and I could not find the answer here. I am trying to do simple testing with Minitest in my Rails API application.
I have two simple models one is Movie:
class CreateMovies < ActiveRecord::Migration[7.0]
def change
create_table :movies do |t|
t.string :title
t.text :synopsis
t.datetime :launch_date
t.string :age_classification
t.string :length
t.string :genre
t.string :director
t.string :poster
t.decimal :rating_avg
t.timestamps
end
end
end
The other one is Sessions
class CreateSessions < ActiveRecord::Migration[7.0]
def change
create_table :sessions do |t|
t.references :movie, null: false, foreign_key: true
t.text :times
t.text :dates
t.timestamps
end
end
end
Testing "should create session" auto-generated testing function:
class SessionsControllerTest < ActionDispatch::IntegrationTest
setup do
@movie = movies(:one)
@session = sessions(:one)
end
test "should create session" do
assert_difference("Session.count") do
post sessions_url, params: { session: { dates: @session.dates, movie_id: @session.movie_id, times: '21:00' } }, as: :json
end
assert_response 201
end
end
I face the following error:
Minitest::UnexpectedError: ActiveRecord::RecordInvalid: Validation failed: Movie must exist
movies.yml
one:
title: Avatar
synopsis: A paraplegic Marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home
launch_date: 18/12/2009
age_classification: 13
length: 162
genre: Action
director: James Cameron
poster: https://m.media-amazon.com/images/M/MV5BNjA3NGExZDktNDlhZC00NjYyLTgwNmUtZWUzMDYwMTZjZWUyXkEyXkFqcGdeQXVyMTU1MDM3NDk0._V1_SX300.jpg
rating_avg: 8.0
sessions.yml
one:
movie: one
times: 16:00
dates: 17/07/2022
I have ensured Movie exists when post line is executing but no clue why is this happening. Any ideas?
PD: Running on Ruby 3.1.2 and Ruby On Rails 7.0.4
I tried to forcefully create a new Movie just before the post statement it did not work. I also tried to output if the movie exists inside controller when it creates the session but it does not save the session because ActiveRecord::RecordInvalid: Validation failed: Movie must exist
.
CodePudding user response:
Your parameters are nested under session
in the request, but your strong parameter method doesn't reflect this nesting.
Change your session_params
method to:
def session_params
params.require(:session).permit(:movie_id, :times, :dates)
end
When you parameters look like this
params = { session: { dates: @session.dates, movie_id: @session.movie_id, times: '21:00' } }
and you only call params.permit(:movie_id, :times, :dates)
then Rails would try to permit those key/value pairs on the other hash. Because those keys do not exist on the outer hash but only on the inner hash, params.permit(:movie_id, :times, :dates)
will return an empty {}
hash.
But when you call params.require(:session).permit(:movie_id, :times, :dates)
, then the require(:session)
will require that there is a session
key on the outer hash and will return its value, which is the inner hash. Then the chained permit(:movie_id, :times, :dates)
call will permit those key/value pairs from the inner hash and will return:
{ dates: @session.dates, movie_id: @session.movie_id, times: '21:00' }
I suggest reading about strong parameters in the official Rails Guides.