JoCoz
JoCoz

Reputation: 11

Rails: "Validation failed: Class must exist" in a Form_with

I've a multiple relation table named Order which belongs_to a Relai(to avoid singular/plurials complications), a Customer and a Composition. I set my Order model accordingly with nested_attributes as mentioned below. Before adding the customer part, I want to send a mail with just the @composition and a @relai chose with a dropdown.

class Order < ApplicationRecord
  belongs_to :relai
  belongs_to :composition
  accepts_nested_attributes_for :relai
  accepts_nested_attributes_for :composition
end

I set my OrdersController to get the :composition_id from my params

def new
    @order = Order.new
    @composition = Composition.find(params[:composition_id])
    @relais = Relai.all
  end

  def create
    @florist = Florist.first
    @composition = Composition.find(params[:composition_id])
    #@relai = Relai.find(params[:relai_id])  # If I add this line it returns "Couldn't find Relai without an ID"
    @order = Order.new(order_params)
    if @order.save!
      raise
      OrderMailer.order_mail(@order).deliver
      redirect_to thanks_purchase_path
    else
      render :new
    end
  end

  private

  def order_params
    params.require(:order).permit(
      florist_attributes: [:id],
      relai_attributes: [:id, :name, :address],
      composition_attributes: [:id, :name]
      )
  end

My View:

  <%= form_with(model: @order, url: composition_orders_path(@composition), local: true) do |compo| %>
    <%= compo.collection_select :relai, @relais, :id, :name %>
    <%= compo.fields_for :composition do |fc| %>
      <%= fc.collection_select :composition, @compositions, :id, :name %>
    <% end %>
    # Start Block that doesn't display the Relai.all
    #<%#= compo.fields_for :relai do |fr| %>
     #<%#= fr.label :relai, 'Ici la liste des relais :' %>
     #<%#= fr.association :relai, collection: @relais %>
     #<%#= fr.association :relai, @relais, :id, :name %>
    #<%# end %>
    # End Block
    <%= compo.submit "MAIL", class: "app-form-button" %>
  <% end %>

And the routes:

resources :compositions, only: [:show, :index] do
    resources :orders, only: [:show, :new, :create, :index]
  end

I also tried:

Can someone explain me why I got a "Validation failed: Relai must exist, Composition must exist" whereas these appears in my params?

{"authenticity_token"=>"[FILTERED]", "order"=>{"relai"=>"2"}, "commit"=>"MAIL", "composition_id"=>"3"}

I'm on Rails 6.1.4 ; Ruby 2.6.6

Upvotes: 0

Views: 187

Answers (1)

CAmador
CAmador

Reputation: 1951

accepts_nested_attributes_for works from parent to children. You are using it on the child side (Order).

If you just need to assign an existing Relai and Composition to Order just use a select for both of them:

class Order < ApplicationRecord
  belongs_to :relai
  belongs_to :composition
end
  def new
    @order = Order.new
    @compositions = Composition.all
    @relais = Relai.all
  end

  def create
    @order = Order.new(order_params)
    if @order.save!
      OrderMailer.order_mail(@order).deliver
      redirect_to thanks_purchase_path
    else
      render :new
    end
  end

  private

  def order_params
    params.require(:order).permit(:relai_id, :composition_id)
  end  
<%= form_with(model: @order, url: composition_orders_path(@composition), local: true) do |compo| %>
    <%= compo.collection_select :relai_id, @relais, :id, :name %>
    <%= compo.collection_select :composition_id, @compositions, :id, :name %>
    <%= compo.submit "MAIL", class: "app-form-button" %>
<% end %>

EDIT: Setting Composition on the controller.

  def new
    composition = Composition.find(params[:composition_id])
    @order = Order.new(composition: composition)    
    @relais = Relai.all
  end

  def create
    @order = Order.new(order_params)
    if @order.save!
      OrderMailer.order_mail(@order).deliver
      redirect_to thanks_purchase_path
    else
      render :new
    end
  end

  private

  def order_params
    params.require(:order).permit(:relai_id, :composition_id)
  end  
<%= form_with(model: @order, url: composition_orders_path(@composition), local: true) do |compo| %>
    <%= compo.collection_select :relai_id, @relais, :id, :name %>
    <%= compo.hidden_field :composition_id %>
    <%= compo.submit "MAIL", class: "app-form-button" %>
<% end %>

Upvotes: 0

Related Questions