chrismccord

chrismccord

Creator of Phoenix

Phoenix v1.3.0-rc.0 released

As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure, first class umbrella project support, and scaffolding that re-enforces phoenix as a web-interface to your greater Elixir application. We have also included a new action_fallback feature in Phoenix.Controller that allows you to translate common datastructures in your domain to valid responses. In practice, this cleans up your controller code and gives you a single plug to handle otherwise duplicated code paths. It is particularly nice for JSON API controllers.

For those interested in a detailed overview of the changes and design decisions, check out my LonestarElixir keynote that just went live: https://www.youtube.com/watch?v=tMO28ar0lW8

To use the new phx.new project generator, you can install the archive with the following command:

$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez

As always, we have an upgrade guide with detailed instructions for migrating from 1.2.x projects: Phoenix 1.2.x to 1.3.0 Upgrade Instructions · GitHub

1.3.0 is a backwards compatible release, so upgrading can be as easy as bumping your :phoenix dep in mix.exs to “~> 1.3”. For those wanting to adopt the new conventions, the upgrade guides will take you step-by-step. Before you upgrade, it’s worth watching the keynote or exploring the design decisions outlined below.

Phoenix 1.3 – Design With Intent

The new project and code generators take the lessons learned from the last two years and push folks towards better design decisions as they’re learning. Changes to new projects include moving web inside lib to avoid any special directories, as well as the introduction of the new Web namespace convention to further signal that your Phoenix related web modules are the web interface into your greater Elixir application. Along with new project structure, comes new phx.gen.html and phx.html.json generators that adopt these goals of isolating your web interface from your domain.

Contexts

When you generate a HTML or JSON resource with phx.gen.html|json, Phoenix will generate code inside a Context, which is simply a well-named module, with well-named functions representing an API boundary to part of your application domain.

For example, to generate a “user” resource we’d run:

$ mix phx.gen.html Accounts User users email:string:unique

Notice how “Accounts” is a new required first parameter. This is the context module where your code will live that carries out the business logic of user accounts in your application. Here’s a peek at part of the code that’s generated:

# lib/my_app/web/controllers/user_controller.ex
defmodule MyApp.Web.UserController do     
  ...
  alias MyApp.Accounts
  
  def index(conn, _params) do
    users = Accounts.list_users()
    render(conn, "index.html", users: users)
  end

  def create(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "user created successfully.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end
  ...
end


# lib/my_app/accounts/accounts.ex

defmodule MyApp.Accounts do
  @moduledoc """
  The boundary for the Accounts system.
  """
  alias MyApp.Accounts.User
  
  def list_users do
    Repo.all(User)
  end
  
  def create_user(attrs \\ %{}) do
    %User{}
    |> user_changeset(attrs)
    |> Repo.insert()
  end
  ...
end

You will also have an Ecto schema generated inside lib/my_app/accounts/user.ex. Notice how our controller calls into an API boundary to create or fetch users in the system. We are still using Ecto, but the database and application logic are separated. Our web-interface doesn’t need to know the details of the storage or DB representatin of our User. The Accounts module could internally store users in an agent, ETS, or elsewhere and our controller code remains untouched.

By asking users to think about the boundaries of their APIs, we end up with more maintainable, well structured code. Additionally, we can get a glimpse of what the application does and its feature-set just be exploring the application directory structure:

lib/my_app
├── accounts
│   ├── user.ex
│   └── accounts.ex
├── sales
│   ├── ticket.ex
│   ├── manager.ex
│   └── sales.ex
├── repo.ex
└── web
    ├── channels
    ├── controllers
    ├── templates
    └── views

With just a glance at the directory structure, we can see this application has a User Accounts system, as well as sales system. We can also infer that there is a natural boundary between these systems thru the sales.ex and accounts.ex modules. We can gain this insight without seeing a single line of code. Contrast that to the previous web/models, which did not reveal any relationship between files, and mostly reflected your database structure, providing no insight on how they actually related to your domain.

We are excited about these changes and their long-term payoff in maintainability. We also feel they’ll lead to sharable, isolated libraries that the whole community can take advantage of – inside and outside of Phoenix related projects.

If you have issues upgrading, please find us on elixir-lang irc or slack and we’ll get things sorted out!

I would also like to give a special thank you to @wojtekmach for his help getting the new generators ready for prime-time. <3

Happy coding! :front_facing_baby_chick::fire:

-Chris

Full changelog:

1.3.0-rc.0 (2017-03-01)

  • Enhancements

    • [Generator] Add new phx.new, phx.new.web, phx.new.ecto
      project generators with improved application structure and support for
      umbrella applications
    • [Generator] Add new phx.gen.html and phx.gen.json resource
      generators with improved isolation of API boundaries
    • [Controller] Add current_path and current_url to generate a
      connection’s path and url
    • [Controller] Introduce action_fallback to registers a plug to
      call as a fallback to the controller action
    • [Controller] Wrap exceptions at controller to maintain connection
      state
    • [Channel] Add ability to configure channel event logging with
      :log_join and :log_handle_in options
    • [Channel] Warn on unhandled handle_info/2 messages
    • [Channel] Channels now distinguish from graceful exits and
      application restarts, allowing clients to enter error mode and
      reconnected after cold deploys.
    • [Router] document match support for matching on any http method
      with the special :* argument
    • [ConnTest] Add redirected_params/1 to return the named params
      matched in the router for the redirected URL
  • Deprecations

    • [Generator] All phoenix.* mix tasks have been deprecated in
      favor of new phx.* tasks
  • JavaScript client enhancements

    • Add ability to pass encode and decode functions to socket
      constructor for custom encoding and decoding of outgoing and incoming
      messages.
    • Detect heartbeat timeouts on client to handle ungraceful
      connection loss for faster socket error detection
    • Add support for AMD/RequireJS

First 10 of 96 Posts Switch mode

ion

ion

Thank you to everyone who worked on this project!

mjrode

mjrode

Thanks for the post Chris. I really love the separation of the application logic and business logic and have been trying to implement it based off your talk from Elixir Conf but it is really helpful to have this post as a walkthrough. Thanks for all of your hard work!

ssboisen

ssboisen

Screaming Architecture :slight_smile: Clean Coder Blog

chrismccord

chrismccord OP

Creator of Phoenix
dgamidov

dgamidov

Great news :tada: Thanks to all Phoenix devs!

dgamidov

dgamidov

Is there a mistake in directory structure in the post - files context.ex are nested in directories?

aptinio

aptinio

@dgamidov seems like they’re on the same level to me.

Thanks Pheonix devs! I’m pretty excited about this one.

navinpeiris

navinpeiris

Yay!! Brilliant!! Thanks for all the hard work all!

In case it’s helpful, I’ve also updated https://www.phoenixdiff.org/ to show the diffs for 1.3.0-rc.0

dgamidov

dgamidov

@aptinio in the post?

Directories accounts and sales are on the same level, but accounts.ex is nested in accounts:

lib/my_app
├── accounts
│   ├── user.ex
│   └── accounts.ex
├── sales

And in keynote blog and sales and blog.ex are on the same level.

krapans

krapans

Looks really promising, can’t wait for final release. :slight_smile:

Where Next?

Trending in Phoenix News Top

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New

We're in Beta

About us Mission Statement