到目前为止,我们已经看到了如何通过Elixir语言使用Erlang VM的基本数据类型和编码原理。 现在,我们将全面介绍并使用Phoenix Web Framework创建一个可运行的Web应用程序。
Phoenix使用MVC服务器端模式,实际上是包含插件 (用于路由 , 控制器等的模块化规范), Ecto (用于MongoDB,MySQL,SQLite3,PostgreSQL的数据库包装器)的多层模块化系统的顶层,以及MSSQL)和HTTP服务器(牛仔)。
Phoenix的结构对于Django for Python或Ruby on Rails来说似乎很熟悉。 应用程序的性能和开发速度都是Phoenix设计的关键因素,与Phoenix的实时功能结合后,它们具有强大的潜力,可作为生产质量的Web应用程序框架。
入门
需要Elixir,因此请参阅本系列开始时的安装说明。
我们还将要求Hex使Phoenix
运行(安装依赖项)。 这是安装Hex的命令(如果已经安装了Hex,它将升级Hex到最新版本):
$ mix local.hex
如果您还不熟悉Elixir语言,建议您继续阅读本指南的第一步,然后再继续进行本部分。
请注意,如果您想阅读简短的指南,还可以参考Phoenix团队提供的Learning Elixir和Erlang指南 。
Erlang
注意:默认情况下,这包含在Elixir安装中。
要运行Elixir,我们需要Erlang虚拟机,因为Elixir代码会编译为Erlang字节码。
如果您使用的是基于Debian的系统,则可能需要显式安装Erlang以获取所有需要的软件包。
wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb
$ sudo apt-get update
$ sudo apt-get install esl-erlang
凤凰
现在我们已经处理了Elixir和Erlang,现在您可以准备安装Mix存档了。
混合存档实际上就像一个Zip文件,不同之处在于它包含一个应用程序以及已编译的BEAM文件,并与该应用程序的特定版本绑定在一起。
我们将使用mix存档生成一个新的基础Phoenix应用程序,从中可以构建我们的应用程序!
在终端中运行以下命令:
$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez
如果无法使用此命令正确安装Phoenix Mix存档,则可以从Phoenix存档中下载该软件包,将其保存到文件系统,然后运行: mix archive.install /path/to/local/phoenix_new.ez
。
节点
我们将需要node.js版本5或更高版本,因为Phoenix将使用brunch.io包来编译诸如css和js之类的静态资产,而静态资产又会使用npm
。
从下载页面下载Node.js。 选择要下载的软件包时,请务必注意Phoenix需要版本5.0.0或更高版本。
Mac OS X用户还可以通过自制软件安装Node.js。
如果您在安装Node时遇到任何问题,请参考Phoenix官方帮助指南。
PostgreSQL的
默认情况下,Phoenix将应用程序配置为使用关系数据库服务器PostgreSQL,但是我们可以在创建新应用程序时通过传递--database mysql
标志来切换到MySQL。
展望未来,在本指南中使用Ecto模型时,我们将使用PostgreSQL和Postgrex适配器。
因此,要跟随示例,您应该安装PostgreSQL。 PostgreSQL Wiki具有用于许多不同操作系统的安装指南 。
请注意,Postgrex是直接的Phoenix依赖项,在我们启动应用程序时,它将与其他依赖项一起自动安装。
默认用户
Phoenix假设我们的PostgreSQL数据库将具有一个具有正确权限的postgres
用户帐户,密码为“ postgres”。 如果那不是您要设置的方式,请参阅ecto.create mix任务的说明以自定义凭据。
骨架安装
如果您只希望裸机运行phoenix应用程序,而没有Ecto或Plug(没有db或brunch.io),请使用以下--no-brunch
和--no-ecto
标志创建您的应用程序:
mix phoenix.new web --no-brunch --no-ecto
飞行前检查
至此,您应该具有:
- 长生不老药
- Erlang(默认情况下由Elixir安装提供)
- 十六进制
- Phoenix Mix档案已安装
- 另外 ,如果您选择了数据库和静态资产支持,那么还将拥有PostgreSQL和Node.js> = 5.0.0,在这种情况下,您现在就可以创建应用了。
建立您的应用程式
您可以从任何目录运行mix phoenix.new
,以引导Phoenix应用程序。
对于您的新项目,Phoenix将接受绝对路径或相对路径; 假设我们的应用程序名称是hello_world
,那么以下两种方法都可以正常工作:
$ mix phoenix.new /home/me/code/hello_world
$ mix phoenix.new hello_world
准备就绪后,运行create命令,您将获得类似于以下输出的信息:
mix phoenix.new hello_world
* creating hello_world/config/config.exs
* creating hello_world/config/dev.exs
* creating hello_world/config/prod.exs
...
* creating hello_world/web/views/layout_view.ex
* creating hello_world/web/views/page_view.ex
Fetch and install dependencies? [Yn]
因此,Phoenix在这里负责为您的应用创建所有目录结构和文件。 您可以通过直接在所选的代码编辑器中导航至文件来查看其创建的内容。
完成后,我们会看到提示要求安装依赖项的提示。 继续是:
Fetch and install dependencies? [Yn] Y
* running mix deps.get
* running npm install && node node_modules/brunch/bin/brunch build
We are all set! Run your Phoenix application:
$ cd hello_world
$ mix phoenix.server
You can also run your app inside IEx (Interactive Elixir) as:
$ iex -S mix phoenix.server
Before moving on, configure your database in config/dev.exs and run:
$ mix ecto.create
现在,所有内容均已下载,我们可以将cd
到Elixir用来填充项目文件的目录中,然后通过mix ecto.create
创建数据库。
$ cd hello_world
$ mix ecto.create
==> connection
Compiling 1 file (.ex)
Generated connection app
==> fs (compile)
Compiled src/sys/inotifywait.erl
Compiled src/sys/fsevents.erl
Compiled src/sys/inotifywait_win32.erl
Compiled src/fs_event_bridge.erl
Compiled src/fs_sup.erl
Compiled src/fs_app.erl
Compiled src/fs_server.erl
Compiled src/fs.erl
...
The database for HelloPhoenix.Repo has been created.
注意:如果这是您第一次运行此命令,Phoenix可能还会要求安装Rebar。 由于Rebar用于构建Erlang软件包,因此请继续进行安装。
数据库问题
如果看到以下错误:
State: Postgrex.Protocol
** (Mix) The database for HelloWorld.Repo couldn't be created: an exception was raised:
** (DBConnection.ConnectionError) tcp connect: connection refused - :econnrefused
(db_connection) lib/db_connection/connection.ex:148: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
请确保PostgreSQL服务正在运行并且可以使用提供的用户凭据进行访问(默认情况下,使用密码为“ postgres”的用户postgres
)。
启动Phoenix Web服务器!
现在我们可以启动Elixir应用程序的服务器! 运行以下命令:
$ mix phoenix.server
[info] Running HelloWorld.Endpoint with Cowboy using http on port 4000
23 Nov 05:25:14 - info: compiled 5 files into 2 files, copied 3 in 1724ms
默认情况下,Phoenix在端口4000上接受请求。
访问http:// localhost:4000 ,您将看到Phoenix框架欢迎页面。

如果看不到上面的页面,请尝试通过http://127.0.0.1:4000访问它(以防在操作系统上未定义localhost的情况下)。
在本地,我们现在可以在终端会话中看到正在处理的请求,因为我们的应用程序正在iex
会话中运行。 要停止它,我们按了ctrl-c
两次,就像我们通常要停止iex
。
$ mix phoenix.server
[info] Running HelloWorld.Endpoint with Cowboy using http://localhost:4000
28 Nov 15:32:33 - info: compiling
28 Nov 15:32:34 - info: compiled 6 files into 2 files, copied 3 in 5 sec
[info] GET /
[debug] Processing by HelloWorld.PageController.index/2
Parameters: %{}
Pipelines: [:browser]
[info] Sent 200 in 50ms
自定义您的应用程序
当Phoenix为我们生成一个新的应用程序时,它会构建一个顶级目录结构,如下面的部分所述。
我们通过mix phoenix.new
命令创建了一个新应用程序,该命令生成了一个新应用程序,包括目录结构:
├── _build
├── config
├── deps
├── lib
├── priv
├── test
├── web
现在,我们将在包含以下内容的Web目录上工作:
├── channels
└── user_socket.ex
├── controllers
│ └── page_controller.ex
├── models
├── static
│ ├── assets
│ | ├── images
| | | └── phoenix.png
| | └── favicon.ico
| | └── robots.txt
│ | ├── vendor
├── templates
│ ├── layout
│ │ └── app.html.eex
│ └── page
│ └── index.html.eex
└── views
| ├── error_helpers.ex
| ├── error_view.ex
| ├── layout_view.ex
| └── page_view.ex
├── router.ex
├── gettext.ex
├── web.ex
要更改页面顶部的徽标,我们需要编辑保存在priv/static
的静态资产。 徽标以如下形式保存在目录中: priv/static/images/phoenix.png
。
随时在此处添加自己的图形; 我们将其链接到CSS中,然后开始修改模板。 默认情况下,Phoenix会将所有静态资产(例如,在这里的images目录中)编译到生产包中。
对于当我们需要js或css的构建阶段时,我们将资产放置在web/static
,并将源文件构建到priv/static
各自的app.js
/ app.css
包中。
修改CSS
CSS的路径是web/static/css/phoenix.css
。 要更改徽标,请查看第29-36行。
/* Custom page header */
.header {
border-bottom: 1px solid #e5e5e5;
}
.logo {
width: 519px;
height: 71px;
display: inline-block;
margin-bottom: 1em;
background-image: url("/images/phoenix.png");
background-size: 519px 71px;
}
进行更改并保存文件,更改将自动更新。
28 Nov 15:49:00 - info: copied gript.png in 67ms
28 Nov 15:49:04 - info: compiled phoenix.css and 1 cached file into app.css in 77ms
28 Nov 15:49:33 - info: compiled phoenix.css and 1 cached file into app.css in 75ms
重新加载您的Web浏览器,或加载http:// localhost:4000 。

修改模板
要更改模板的内容,只需查看web/templates/layout
和web/templates/page
。 您可以开始修改文件以查看应用程序中实时的更改。
标准的Phoenix模板引擎使用EEx,代表嵌入式Elixir 。 所有模板文件都具有扩展名.eex
。
模板的作用域是视图,而视图的作用域是控制器。
Phoenix创建了一个web/templates
目录,我们可以在其中放置所有这些内容。 为了便于组织,最好对它们进行命名空间,因此,如果要创建一个新页面,则意味着需要在web/templates
下创建一个新目录,然后在其中创建index.html.eex
文件(例如web/templates/<My-New-Page>/index.html.eex
)。
现在开始吧。 创建web/templates/about/index.html.eex
并使其如下所示:
<div class="jumbotron"> <h2>About my app</h2> </div>
观看次数
在Phoenix中,MVC设计范例的视图部分执行了一些重要的工作。
首先,视图呈现模板。 此外,它们充当来自控制器的原始数据的表示层,充当准备将其用于模板时的中间人。
例如,采用一个通用的假设数据结构,该结构用first_name
字段和last_name
字段代表用户。 现在,对于模板,我们要显示用户的全名。
为了获得最佳方法,我们编写了一个函数来连接first_name
和last_name
并在视图中为我们提供帮助,以编写简洁,简洁且易读的模板代码。
为了呈现AboutController的任何模板,我们需要一个AboutView
。
注意:名称在这里很重要-视图和控制器名称的第一部分必须匹配。
创建web/views/about_view.ex
并使其如下所示:
defmodule HelloWorld.AboutView do
use HelloWorld.Web, :view
end
路由
为了查看新页面,您将需要为视图和模板设置路线以及控制器。
Phoenix在MVC范例上工作时,我们需要填写所有部分。 不过这没什么大不了的。
用简单的英语来说:路由将唯一的HTTP动词/路径对映射到控制器/动作对,以进一步执行。
Phoenix会在web/router.ex
的新应用程序中自动为我们生成一个路由器文件。 这是我们将在以下部分中进行的工作。
默认“欢迎来到凤凰城”的路线。 页面看起来像这样。
get "/", PageController, :index
这意味着捕获通过在浏览器中访问http:// localhost:4000 /发出的所有请求(发出HTTP GET
请求)到应用程序/
根路径的所有请求,并将所有这些请求发送到HelloPhoenix.PageController
模块中的index
函数。在web/controllers/page_controller.ex
定义。
当我们将浏览器指向http:// localhost:4000 / about时,我们将要构建的页面将仅显示“关于我的应用程序”。 您可以在模板中填写更多信息以适合您的应用程序,因此只需继续编写HTML即可!
新路线
对于我们的About页面,我们需要定义一条路线。 因此,只需在文本编辑器中打开web/router.ex
。 默认情况下,它将包含以下内容; 有关路由的更多信息,请参阅正式的《路由指南》 。
defmodule HelloPhoenix.Router do
use HelloPhoenix.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
# Other scopes may use custom stacks.
# scope "/api", HelloPhoenix do
# pipe_through :api
# end
end
对于我们的about部分,让我们将新路由添加到路由器,以向/about
发出GET
请求。 它将由HelloPhoenix.AboutController
处理,我们将在下一部分中对其进行构造。
对于/about
的GET
,将此行添加到router.ex
的scope "/"
块中:
get "/about", AboutController, :index
完整的块如下所示:
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
get "/about", AboutController, :index
end
控制器
我们已经设置了路线,视图和模板。 现在让我们将所有部分放在一起,以便我们可以在浏览器中查看它。
控制器被定义为Elixir模块,控制器内部的动作是Elixir函数。 动作的目的是收集任何数据并执行渲染所需的任何任务。
对于/about
路由,我们需要一个带有index/2
动作的HelloWorld.AboutController
模块。
为此,我们需要创建一个web/controllers/about_controller.ex
并将以下内容放入其中:
defmodule HelloWorld.AboutController do
use HelloWorld.Web, :controller
def index(conn, _params) do
render conn, "index.html"
end
end
有关控制器的更多信息,请参阅《 官方控制器指南》 。
控制器结构
所有控制器动作都带有两个参数。 其中第一个是conn
,它是一个包含有关请求的数据负载的结构。
第二个是params
,它们是请求参数。 在这里,我们不使用params
,而是通过添加前导_
避免编译器警告。
此操作的核心是render conn, "index.html"
。 这告诉Phoenix找到一个名为index.html.eex
的模板并进行渲染。 Phoenix将在以我们的控制器命名的目录中查找模板,因此为web/templates/hello
。
注意:使用原子作为模板名称也可以在这里使用: render conn, :index
,例如,当使用:index
原子时。 但是将根据Accept标头选择模板,例如“ index.html”或“ index.json”。
测试新路线
现在访问http:// localhost:4000 / about URL将呈现我们到目前为止定义的模板,控制器,视图和路由!

动作
因此,现在我们创建了一个页面并对该应用程序进行了一些自定义。 但是,我们实际上如何使用用户输入来做某事? 动作。
关于我们页面的请求将由HelloWorld.AboutController
使用show动作处理。 正如我们在最后一步中定义了控制器一样,我们只需要向代码添加一种保留变量的方法,该变量是通过URL传递的,例如: http:// localhost:4000 / about / weather 。
现在,我们将使用Elixir的模式匹配修改代码,以通过控制器将新的URL GET
请求参数映射到模板,并最终映射到模板。
将以下内容添加到web/controllers/about_controller.ex
的模块中:
def show(conn, %{"appName" => appName}) do
render conn, "show.html", appName: appName
end
这里的一些兴趣点:
- 我们对传递给show函数的参数进行模式匹配,以便将
appName
变量绑定到URL中的值。 - 对于我们的示例URL( http:// localhost:4000 / about / weather ),
appName
变量将包含值weather。 - 在
show
动作中,还为render函数传递了第三个参数: 键/值对 ,其中原子:appName
是键,而appName
变量作为值传递。
web/controllers/about_controller.ex
的完整清单如下:
defmodule HelloWorld.AboutController do
use HelloWorld.Web, :controller
def index(conn, _params) do
render conn, "index.html"
end
def show(conn, %{"appName" => appName}) do
render conn, "show.html", appName: appName
end
end
嵌入式长生不老药
要最终首先在模板中使用变量,我们需要为show动作创建一个文件。
创建文件web/templates/about/show.html.eex
并添加以下内容:
<div class="jumbotron"> <h2>About <%= @appName %></h2>
对于嵌入式Elixir,我们使用特殊的EEx <%= %>
语法。 开头的标签带有=
符号,表示将执行之间的Elixir代码,然后输出将替换该标签。
应用名称的变量显示为@appName
。 在这种情况下,这不是模块属性,但实际上,它是Map.get(assigns, :appName)
的特殊元编程语法。 结果在眼睛上更漂亮,并且在模板中更容易使用。
定义路线
例如,要使我们能够看到路由http:// localhost:4000 / about / weather ,我们需要定义路由以与刚刚定义的控制器的show
action链接。
scope "/", HelloWorld do
pipe_through :browser # Use the default browser stack.
get "/", PageController, :index
get "/about", AboutController, :index
get "/about/:appName", AboutController, :show
end
现在我们的工作完成了! 通过访问URL http:// localhost:4000 / about / weather进行尝试。

结论
现在,您已具备创建Phoenix应用程序,以图形方式对其进行自定义以及为应用程序创建路线,操作,控制器和视图的基本知识。
我们谈到了Ecto的PostgreSQL功能设置,但是要进一步了解MVC范例的Model部分,请继续阅读Ecto指南 。
例如,关于用户交互和创建身份验证,请继续在Phoenix官方文档的Plug指南中学习。
翻译自: https://code.tutsplus.com/tutorials/elixir-walkthrough-part-5-phoenix-framework--cms-27669