Validation failed Class must exist
Asked Answered
F

8

66

I have been (hours) trouble with associations in Rails. I found a lot of similar problems, but I couldn't apply for my case:

City's class:

class City < ApplicationRecord
  has_many :users
end

User's class:

class User < ApplicationRecord
  belongs_to :city

  validates :name, presence: true, length: { maximum: 80 }
  validates :city_id, presence: true
end

Users Controller:

def create
    Rails.logger.debug user_params.inspect
    @user = User.new(user_params)
    if @user.save!
      flash[:success] = "Works!"
      redirect_to '/index'
    else
      render 'new'
    end
 end

def user_params
  params.require(:user).permit(:name, :citys_id)
end

Users View:

<%= form_for(:user, url: '/user/new') do |f| %>
  <%= render 'shared/error_messages' %>

  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.label :citys_id, "City" %>
  <select name="city">
    <% @city.all.each do |t| %>
      <option value="<%= t.id %>"><%= t.city %></option>
    <% end %>
  </select>
end

Migrate:

class CreateUser < ActiveRecord::Migration[5.0]
  def change
    create_table :user do |t|
      t.string :name, limit: 80, null: false
      t.belongs_to :citys, null: false
      t.timestamps
  end
end

Message from console and browser:

ActiveRecord::RecordInvalid (Validation failed: City must exist):

Well, the problem is, the attributes from User's model that aren't FK they are accept by User.save method, and the FK attributes like citys_id are not. Then it gives me error message in browser saying that "Validation failed City must exist".

Thanks

Fielding answered 16/8, 2016 at 20:13 Comment(1)
Possible duplicate of Add nullable foreign keyConduction
O
125

Try the following:

belongs_to :city, optional: true

According to the new docs:

4.1.2.11 :optional

If you set the :optional option to true, then the presence of the associated object won't be validated. By default, this option is set to false.

Olsewski answered 17/8, 2016 at 0:53 Comment(3)
Hey Igor.. it's nice to see a BR here :) Thank you for your answer. It worked! I found this answer earlier, but I didn't have tried until now. The reason was that it seems to me this option invalidate the attributer's validation in a server level. So I checked to be sure, when I give a wrong value to the foreign key city_id the error message just show up after the DB tried to make a insertion query, it seems to me a DB level validation. Anyways, I will make my own validation in a server level to solve this. I would like to give you a UPVOTE, but I don't have enough score :( hahaFielding
ohhh, I didn't know that! hahaha nice :)Fielding
Argh this is quite an annoying gotcha. In FactoryGirl, if you simply make a factory for User without that snippet, in the belongs_to class, you will get that error. Good catch!Mistiemistime
M
15

This comes a bit late but this is how to turn off this by default in rails 5:

config/initializers/new_framework_defaults.rb

Rails.application.config.active_record.belongs_to_required_by_default = false

In case you don't want to add optional: true to all your belongs_to.

I hope this helps!

Moraine answered 14/8, 2017 at 11:9 Comment(1)
I upgraded to Mac OS Mojave yesterday and now I'm getting these validation errors, even though my project has set this to false (since we upgraded to Rails 5 way back when). Anyone know what makes this happen?Moen
C
4

You need to add the following to the end of the belongs_to relationship statement:

optional: true

It is possible to set this on a global level so that it works in the same way as older versions of rails, but I would recommend taking the time to manually add it to the relationships that really need it as this will cause less pain in the future.

Centra answered 14/8, 2017 at 13:20 Comment(0)
F
3

I found out a solution to the problem "Validation failed: Class must exist" and it's better than use:

belongs_to :city, optional: true

4.1.2.11 :optional

If you set the :optional option to true, then the presence of the associated object won't be validated. By default, this option is set to false.

cause you still make a validation in application level. I solve the problem making my own validation in create method and changing user_params method:

def create

  @city = City.find(params[:city_id])

  Rails.logger.debug user_params.inspect
  @user = User.new(user_params)

  @user.city_id = @city.id

  if @user.save!
    flash[:success] = "Works!"
    redirect_to '/index'
  else
    render 'new'
  end
end

def user_params
  params.require(:user).permit(:name)
end

I didn't test this code, but it works in another project mine. I hope it can help others!

Fielding answered 5/4, 2017 at 12:27 Comment(0)
S
2

Rails 5

If you have a belongs_to relationship to :parent then you have to pass an existing parent object or create a new one then assign to children object.

Serin answered 18/4, 2018 at 15:38 Comment(2)
Can you provide example? As I would prefer not to use optional: trueFence
I also need an example. Learning rails and I just can't find how would I do this.Example
M
1
belongs_to :city, required: false
Mabuse answered 25/7, 2017 at 10:41 Comment(1)
Please try to give an explanation to answer the question and not just post code. Thanks.Patois
P
1
params.require(:user).permit(:name, :citys_id)

It's a mistake, isn't it? (citys_id vs city_id)

Propellant answered 25/8, 2020 at 12:50 Comment(2)
yeah, it's. The values on the permit must match with the ones come from the views. You can see these values on your console after a submit.Fielding
Yours mistake helps me understand i have similar problem: I swapped two chars on the field name.Propellant
H
0
Rails.application.config.active_record.belongs_to_required_by_default = false

This works because the Rails 5 has true by default to disable you go under Initilizers then click on the New_frame-work and turn the true to false

Hexagram answered 17/5, 2020 at 16:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.