Never Look Back - Phoenix - The Framework That Respects You
Chapter 4: Phoenix - The Framework That Respects You
If Elixir is the language, Phoenix is its web-facing manifestation. And while it shares some superficial similarities with Rails (it has controllers, views, and a router), its philosophy is fundamentally different. Phoenix values explicitness over magic.
-
Ecto and Changesets: Sanity in Data Handling
Ecto is the database wrapper and query language for Phoenix. It is not an ActiveRecord clone. Its most important innovation is the
Changeset.In Rails, validation rules live on the model. When you call
model.valid?, it checks its internal state. When you callmodel.update(params), it tries to update its attributes and save, all in one go.In Phoenix, data and validation are decoupled. A changeset is a dedicated data structure that represents a proposed change.
def changeset(user, attrs) do user |> cast(attrs, [:name, :email]) |> validate_required([:name, :email]) |> validate_format(:email, ~r/@/) |> unique_constraint(:email) endThis function takes a
userstruct and a map ofattrs(the incoming parameters). It then pipes this data through a series of transformations and validations.cast: Specifies which attributes are allowed to be changed. This is a security-first default.validate_required: Checks for presence.validate_format: Checks against a regex.unique_constraint: Checks for uniqueness at the database level.
The key is that this function returns a changeset. The changeset contains the original data, the proposed changes, a list of validations, and a
valid?flag. No side effects have occurred. The database has not been touched.Your controller then explicitly uses this changeset to perform the database operation:
case MyApp.Accounts.create_user(params) do {:ok, user} -> # Redirect to show page {:error, %Ecto.Changeset{} = changeset} -> # Re-render the form, passing the changeset back # so we can display detailed error messages. render(conn, "new.html", changeset: changeset) endThis explicitness is liberating. The flow of data is crystal clear. There is no hidden state, no callback spaghetti. You can see the transformation of data from raw parameters to a validated changeset to a database insert. It’s more verbose than Rails, but that verbosity buys you clarity, security, and maintainability.
-
Plug: A Composable Architecture
Phoenix is built on a specification called
Plug. A plug is just a function that takes a connection struct (conn) and some options, and returns a (possibly modified)conn.Your entire request-response lifecycle is a pipeline of plugs.
pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_live_flash plug :protect_from_forgery plug :put_secure_browser_headers endThis is from the router. When a request comes in, it flows through each of these plugs in order.
fetch_sessionloads the session data into theconn.protect_from_forgeryvalidates the CSRF token. Controllers themselves are just plugs. This is a beautifully simple and composable idea. It’s Elixir’s functional nature applied to the web. It’s explicit, easy to follow, and easy to test.
Read prev: A New Paradigm: The Elixir of Life | Read next: The Real-Time Revolution with LiveView