Forms & Strong Parameters
📋 Forms & Strong Parameters
create and update, the security mechanism preventing a submitted form from setting fields it shouldn't, and the CSRF protection every one of Rails' forms has been quietly including the entire time.
📝 form_with
form_with model: post inspects the post object and automatically decides everything Express would need spelled out by hand: a new, unsaved Post generates a form that POSTs to /posts (the create action); an existing, persisted Post generates a form that submits as PATCH to /posts/:id (the update action) — the same partial (from Chapter 4) works for both the new and edit views without any conditional logic inside it.
🏷️ Field Helpers Generate Rails-Shaped Names
f.text_field :title generates an input with name="post[title]" — matching Chapter 3's nested params[:post][:title] structure automatically. In Express + EJS, this nesting has to be hand-built: writing name="title" directly, or manually adopting a naming convention like name="post[title]" yourself with no framework enforcement or generation.
⚠️ Displaying Validation Errors
This is Chapter 7's errors.full_messages put to work: when create fails and re-renders :new (Chapter 3), the same @post instance — invalid, but still holding the user's submitted values and the validation errors — flows straight into this partial with no extra wiring.
🔒 Strong Parameters
params.require(:post) raises an error if the post key is missing entirely; .permit(:title, :body, :published) explicitly whitelists exactly which fields are allowed through — anything else submitted in the form gets silently dropped, never reaching Post.new.
Imagine Post.new(params[:post]) instead — passing the entire submitted hash straight into the model with no whitelist. If Post ever gains an admin_only or featured boolean column, a malicious user could add a hidden field, post[featured]=true, to their form submission (using browser dev tools, or a crafted request bypassing the UI entirely) and set a field the form never intended to expose. This is a mass assignment vulnerability — trusting raw user input to determine which attributes get set, the same "never trust user input" principle underlying every completed security course, just applied specifically to model attribute assignment.
🛡️ CSRF Protection, Built In
Recall the completed CSRF security course: preventing cross-site request forgery requires a unique, unpredictable token embedded in every form and verified on submission. Rails generates this automatically — protect_from_forgery is present in ApplicationController from the moment rails new runs (Chapter 1), and every form_with call silently embeds the token as a hidden field with zero additional code required.
CSRF Protection: Express vs Rails
| Step | Express | Rails |
|---|---|---|
| Enable protection | Install and configure csurf (or a modern equivalent) manually | On by default — no setup required |
| Embed the token in a form | Manually add a hidden input with the token, in every form | Automatic — form_with does it for you |
| Verify on submission | Middleware you wired up yourself | Automatic — built into ApplicationController |
💻 Coding Challenges
Challenge 1: A Product Form
Write app/views/products/_form.html.erb using form_with model: product with fields for name (text field), description (text area), and in_stock (checkbox), plus a submit button.
Goal: Practice the standard form_with + field helper pattern for a realistic set of field types.
Challenge 2: Strong Parameters and a Mass Assignment Attack
Write the product_params private method for a ProductsController, permitting only name, description, and price — deliberately excluding a featured boolean column that exists on the table. Then write two sentences describing exactly what a malicious form submission would need to include to try to set featured, and why product_params as written stops it.
Goal: Understand strong parameters as an active defense, not just boilerplate.
Challenge 3: Displaying Errors in a Form
Add an error-display block (following this chapter's pattern) above a form_with model: product form, then trace through what happens end to end: a user submits an invalid product, create fails, and the form re-renders. Write out, step by step, which chapter's concept handles each part of that flow (validation, the branch in the controller, the errors object, the re-rendered view).
Goal: Connect this chapter's form back to the validations (Chapter 7) and controller logic (Chapter 3) it depends on.
Look back across this course: automatic HTML escaping (Chapter 4), automatic SQL injection protection through the query interface (Chapter 5), and now strong parameters and built-in CSRF protection — every one of them is the same underlying pattern this course keeps returning to. Rails doesn't just make the common case shorter to write; it consistently makes the common case the secure case, requiring a deliberate, visible opt-out (raw(), string-interpolated SQL, skipping permit) to reach the dangerous version instead of a deliberate opt-in to reach the safe one.
🎯 What's Next
Course 1 (Ruby on Rails Fundamentals) is complete. Ruby on Rails Intermediate/Advanced (Course 2) begins with Authentication — has_secure_password/bcrypt and session-based login, contrasted with Express's typical JWT-based approach.