Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation failed Class must exist

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

like image 293
Pedro Gabriel Lima Avatar asked Aug 16 '16 20:08

Pedro Gabriel Lima


5 Answers

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.

like image 142
Igor_Marques Avatar answered Nov 08 '22 20:11

Igor_Marques


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!

like image 45
Jeremie Avatar answered Nov 08 '22 20:11

Jeremie


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.

like image 4
David Kane Avatar answered Nov 08 '22 21:11

David Kane


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!

like image 3
Pedro Gabriel Lima Avatar answered Nov 08 '22 20:11

Pedro Gabriel Lima


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.

like image 2
ricks Avatar answered Nov 08 '22 19:11

ricks