Search code examples
ruby-on-railsrubytestingminitestruby-on-rails-7

Error Rails Minitest in simple post request


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.


Solution

  • 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.