I'm new to rails- but now wondering, are Rails validations lost on model objects when in my form I'm trying to create both the child and parent at the same time?
In my example (models in bold) 1 - Cake - has_many - CakeDetails
many - CakeDetails - belong_to 1 - Size
1 - CakeType - belongs_to 1 - Cake
I've managed to create a form That allows me to create a Cake, specify the sizes, associated prices and what type the cake will be.
But it seems all built in model validation is gone.
Is this correct? How do I bring validation back to my model objects?
When I render the new action I bring up a blank form and when I submit a blank form I get the following:
Started POST "/cakes" for 127.0.0.1 at 2018-04-25 21:19:03 +0100
Processing by CakesController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"r6B2ult7w7z4vez95f2pNXmk7Q1rYSzj8Wi9VwnS4EgIAw8PG/w7isfAeiiSB9sY8+0+oHldMVpy1GFKBmrpmw==", "cake"=>{"name"=>"", "description"=>"", "cake_type_id"=>"", "cake_details_attributes"=>{"0"=>{"_destroy"=>"true", "price"=>""}, "1"=>{"_destroy"=>"true", "price"=>""}}}, "commit"=>"Create Cake"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
Rendering cakes/new.html.erb within layouts/application
CakeType Load (0.3ms) SELECT "cake_types".* FROM "cake_types"
Rendered cakes/_form.html.erb (15.9ms)
Rendered cakes/new.html.erb within layouts/application (19.6ms)
Completed 200 OK in 109ms (Views: 100.4ms | ActiveRecord: 0.5ms)
I get that its rolling back the transaction because there is no cake_type_id. But there is no errors displayed.
The following is the error displaying section in my form. I've tried adding more to check for errors in the nested object but not seeing anything.
<% if @cake.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(cake.errors.count, "error") %> prohibited this cake from being saved:</h2>
<ul>
<% @cake.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<% @cake.cake_details.each do |detail| %>
<% if detail.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(cake.errors.count, "error") %> prohibited this cake from being saved:</h2>
<ul>
<% @cake.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
My Cake model
class Cake < ApplicationRecord
validates :name, :description, :cake_type, presence: true
belongs_to :cake_type
has_many :cake_details, -> {order('size_id ASC')}, inverse_of: :cake
has_many :sizes, through: :cake_details
accepts_nested_attributes_for :cake_details, :allow_destroy => true
validates_associated :cake_type, :cake_details
end
Cakes Controller
def create
#@cake = Cake.new(params[cake:{}])
#params.require(:cake).permit(:name, :description,:cake_type_id)
@cake = Cake.new(cake_params)
respond_to do |format|
if @cake.save
format.html { redirect_to @cake, notice: 'Cake was successfully created.' }
format.json { render :show, status: :created, location: @cake }
else
format.html { render :new }
format.json { render json: @cake.errors, status: :unprocessable_entity }
end
end
end
def cake_only_params
params.require(:cake).permit(:name, :description,:cake_type_id)
end
def cake_params
params.require(:cake).permit(:name, :description,:cake_type_id, cake_type_id:[:type_id],
cake_details_attributes:[:_destroy, :id, :cake_id, :size_id, :price])
end
UPDATE
I thought I had to access the variable I declared in my action e.g @cake but I updated my form to use this
<%= form_with(model: cake, local: true) do |form| %>
instead of how I thought I needed it:
<%= form_with(model: @cake) do |form| %>
I'll read up on the docs but any comments on why I messed this up is definitely appreciated. Just starting to learn this framework... :/
I thought I had to access the variable I declared in my action e.g
@cake
but I updated my form to use this:
<%= form_with(model: cake, local: true) do |form| %>
instead of how I thought I needed it:
<%= form_with(model: @cake) do |form| %>
and that works now.
Special thanks to jvillian for responding so quickly.
And noting that:
By adding local: true
to form_with
, you force the form to submit as html
and your controller then uses format.html
.