Challenge 3: Displaying Errors in a Form — Solution <% if product.errors.any? %>
<% end %> <%= form_with model: product do |f| %> <%= f.text_field :name %> <%= f.submit %> <% end %> Step-by-step trace of an invalid submission: 1. (Chapter 7) The Product model has validates :name, presence: true (or similar) declared directly on the model. 2. (Chapter 3) A user submits the form with a blank name. The create action runs: @product = Product.new(product_params); if @product.save ... else render :new end. Because validation fails, .save returns false, so the else branch runs: render :new. 3. (Chapter 7) The failed .save call populated @product.errors automatically -- @product itself is still in memory with the user's submitted (invalid) values, exactly as it was built from product_params moments earlier. 4. (Chapter 3 + this chapter) render :new re-renders the SAME @product instance -- no new HTTP request is made, no database re-query happens -- straight into app/views/products/new.html.erb, which itself renders this chapter's _form.html.erb partial. 5. (This chapter) product.errors.any? is now true, so the error block at the top of the partial displays every message from product.errors.full_messages, and the form fields below still show the user's originally submitted (invalid) values, ready to be corrected and resubmitted. =begin Notes: - Nothing in this flow involves a second HTTP request -- render :new (as opposed to redirect_to) is specifically what keeps @product's in-memory state, including both its errors and the user's typed input, intact through to the re-rendered form. - This end-to-end trace is really the payoff of five separate chapters (validations, controllers, views, and this chapter's forms) all working together on one single, ordinary "submit an invalid form" interaction. =end