Some time ago I actually initiated my very first Phoenix app, but was a bit disappointed by the lack of a rich box of gems (like that of ruby’s) and/or I didn’t have the time to invest heavily in researching all the possibilities. One of my new year resolution was to actively pursue more knowledge, hence I’m giving it a second shot.
I’m a full-stack Rails developer, but I needed real time messaging. That is not something Rails is typically good at (although it works), but Elixir (with its Erlang base) is well known for, even in the ruby community. Phoenix wraps Elixir in a nice Rails-like package ready for web and API development.
brew install elixir
) and make sure you have node.js installed (for frontend compiling) (macOS & homebrew: brew install nodejs
)Get the mix-packagemangager:
$ mix local.hex
Then install Phoenix:
mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez`
Typically a Phoenix app uses a PostgreSQL database. We assume it being installed; alternatively you can opt to use MySQL by passing the --database mysql
option with the new command
Simply run the following command to get the base (and see above, you might add —database mysql
when you’re not a PostgreSQL’er)
$ mix phoenix.new web
Hit Y
(es) when asked for installing de dependencies. In case you want to change de default database (a PostgreSQL database named {applicationname}_dev
) change it in config/dev.exs
. Then navigate to the project’s dir (cd web
in this case) run to prepare the database:
mix ecto.create
Run the server (it’ll run on port 4000 by default).
mix phoenix.server
When using rails I typically use the Devise-gem. When browsing for packages at the Awesome-Elixir-page I came across Coherence which felt kind of the same.
Hence I added {:coherence, "~> 0.3"}
(a later version may be available, check the above links) to the deps
block in the mix.exs
file. deps
is defined as a private function (defp deps do … end
-block). It could’ve been defined as a non private function (def deps…
(note without the p)).
Then add :coherence
as the first in the array of applications to load within the application
definition, mine now looks like this:
applications: [:coherence, :phoenix, :phoenix_pubsub, :phoenix_html…]]
Then install it, which will set up some database migrations for a newly to create User model and more:
mix coherence.install --full-confirmable
Then update the web/router.ex
file to use the coherence routes and route-based authentication-filtering (or should I say piping):
Add:
# just after ` use MyProject.Web, :router`
use Coherence.Router # Add this
# last line in the `pipeline :browser do … end`-block
plug Coherence.Authentication.Session
# Add the following three blocks after the `pipeline :browser`-block
pipeline :protected do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Coherence.Authentication.Session, protected: true
end
scope "/" do
pipe_through :browser
coherence_routes
end
scope "/" do
pipe_through :protected
coherence_routes :protected
end
Also don’t forget to run the migrations:
mix ecto.setup
Now you’ll have a full user-table and you’re ready to register users!
You want the application to reflect that the user is signed in (e.g. show a sign in link when not logged in, show a sign out link when logged in)
Adding a link to sign in using the link-helper:
<%= if Coherence.current_user(@conn) do %>
<li><%= button('Uitloggen', to: session_path(@conn, :delete, Coherence.current_user(@conn).id), method: :delete) %></li>
<% else %>
<li><%= link('Register', to: registration_path(@conn, :new)) %></li>
<li><%= link('Sign in', to: session_path(@conn, :new)) %></li>
<% end %>
TrueProgrammers™ will probably hate it, but I’m going to simply do the Phoenix equivalent of rails scaffold
(note the ‘repetition’ of posts
in the line, this is the table-name):
$ mix phoenix.gen.html Post posts message:text user_id:references:users
In contrast to a rails scaffold
, you do have to ‘manually’ place the following line in the scope "/", Lokal do … end
-block in router.ex
.:
resources "/posts", PostController
And of course you need to migrate your database:
mix ecto.migrate
We don’t want just anyone to update posts, hence we add at the top of our PostsController:
plug Coherence.Authentication.Session, [login: true, protected: true] when (action != :index and action != :show)
The login: true
, makes sure the user is redirected to the login page on all actions but :index
and :show
.
Almost forgot about this one. You want to know which user posted what, hence we update post_controller.ex
and update the create block:
def create(conn, %{"post" => post_params}) do
user = Coherence.current_user(conn)
changeset = Post.changeset(%Post{user: user}, post_params)
...
end
We’ve now created a new changeset including the new user params. In case you’re wondering, like I was, whether this doesn’t open up overriding the actual user attribution? Well, since the model (in post.ex
) describes how to cast the parameters to a proper changeset, which doesn’t include a user, nor a user_id, it won’t pass any user changes :)
The Phoenix-framework is very much Rails like. But when searching for a proper authentication gem I didn’t find something that was as complete as e.g. Devise is. But all is under heavy development.
Also I missed kind of the ruby approach where functional programming is allowed but at the same time everything is an object as well. I really enjoy writing:
[1,2,3,4].include? 3
Instead, Elixir has only what you would call class-methods in ruby that allow you to search lists, which make it more verbose. You have to think about what type of data structure you’re dealing with. Of course, that’s kind of the nature of a pure functional programming language
I haven’t dealt with the primary reason I wanted to check Phoenix out for in the first place, the promised speed in dealing with messaging (because of Elixer running in the Erlang VM).
That’s it for now! Next will be pushing it real time to the subscribed audience :)
Enjoyed this? Follow me on Mastodon or add the RSS, euh ATOM feed to your feed reader.
Dit artikel van murblog van Maarten Brouwers (murb) is in licentie gegeven volgens een Creative Commons Naamsvermelding 3.0 Nederland licentie .