{"id":281688,"date":"2016-11-29T03:00:04","date_gmt":"2016-11-29T00:00:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=281688"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=281688","title":{"rendered":"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u0432\u0438\u0436\u043a\u0430 \u0434\u043b\u044f \u0431\u043b\u043e\u0433\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Phoenix \u0438 Elixir \/ \u0427\u0430\u0441\u0442\u044c 4. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0440\u043e\u043b\u0435\u0439 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/81c\/359\/9c0\/81c3599c01a1461aa1ecf172a495a750.png\"\/><\/p>\n<p>  \u041e\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0447\u0438\u043a\u0430: \u00ab<i>Elixir \u0438 Phoenix \u2014 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0443\u0434\u0430 \u0434\u0432\u0438\u0436\u0435\u0442\u0441\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430. \u0423\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0421\u0430\u0439\u0442\u044b \u0441 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e, \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0438\u0433\u0440\u044b, \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u2014 \u0442\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0441\u043e\u0441\u043b\u0443\u0436\u0430\u0442 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u0441\u043b\u0443\u0436\u0431\u0443. \u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0435\u0440\u0438\u0438 \u0438\u0437 11 \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u0424\u0435\u043d\u0438\u043a\u0441 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b \u0442\u0430\u043a\u043e\u0439 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0449\u0438, \u043a\u0430\u043a \u0431\u043b\u043e\u0433\u043e\u0432\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a. \u041d\u043e \u043d\u0435 \u0441\u043f\u0435\u0448\u0438\u0442\u0435 \u043a\u0443\u043a\u0441\u0438\u0442\u044c\u0441\u044f, \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e\u0431\u0443\u0434\u044f\u0442 \u0432\u0430\u0441 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u042d\u043b\u0438\u043a\u0441\u0438\u0440 \u043b\u0438\u0431\u043e \u0441\u0442\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0440\u0430\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u043e\u043b\u0435\u0439. \u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u2014 \u0437\u0434\u0435\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0443\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0430\u043c, \u0430 \u0442\u0435\u0441\u0442\u044b \u2014 \u044d\u0442\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u043e!<\/i><\/p>\n<p>  \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043e \u043d\u0430:<\/p>\n<ul>\n<li><b>Elixir<\/b>: v1.3.1<\/li>\n<li><b>Phoenix<\/b>: v1.2.0<\/li>\n<li><b>Ecto<\/b>: v2.0.2<\/li>\n<li><b>Comeonin<\/b>: v2.5.2<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u0413\u0434\u0435 \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c<\/h2>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0440\u0430\u0441\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0441 \u0432\u0430\u043c\u0438 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u0440\u043e\u043b\u0438 \u0432\u043d\u0443\u0442\u0440\u044c \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0436\u0438\u0437\u043d\u044c. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0440\u043e\u043b\u044f\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435.<\/p>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u043e\u043b\u0435\u0439<\/h2>\n<p>  \u041f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0441\u0442\u0430\u043d\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043f\u0440\u0430\u0432 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>web\/models\/role_checker.ex<\/code> \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c:<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<pre><code>defmodule Pxblog.RoleChecker do   alias Pxblog.Repo   alias Pxblog.Role    def is_admin?(user) do     (role = Repo.get(Role, user.role_id)) && role.admin   end end<\/code><\/pre>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>test\/models\/role_checker_test.exs<\/code>:<\/p>\n<pre><code>defmodule Pxblog.RoleCheckerTest do   use Pxblog.ModelCase   alias Pxblog.TestHelper   alias Pxblog.RoleChecker    test &quot;is_admin? is true when user has an admin role&quot; do     {:ok, role} = TestHelper.create_role(%{name: &quot;Admin&quot;, admin: true})     {:ok, user} = TestHelper.create_user(role, %{email: &quot;test@test.com&quot;, username: &quot;user&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})     assert RoleChecker.is_admin?(user)   end    test &quot;is_admin? is false when user does not have an admin role&quot; do     {:ok, role} = TestHelper.create_role(%{name: &quot;User&quot;, admin: false})     {:ok, user} = TestHelper.create_user(role, %{email: &quot;test@test.com&quot;, username: &quot;user&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})     refute RoleChecker.is_admin?(user)   end end<\/code><\/pre>\n<p>  \u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430, \u0430 \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0410 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>is_admin?<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>true<\/code> \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0438 <code>false<\/code> \u0434\u043b\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e. \u0422\u0430\u043a \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>is_admin?<\/code> \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f <code>RoleChecker<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u0441\u0442, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u0440\u0435\u043d\u044b! \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b \u0438 \u0443\u0431\u0435\u0436\u0434\u0430\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d\u0438 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u0437\u0435\u043b\u0451\u043d\u044b\u043c\u0438.<\/p>\n<h2>\u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443<\/h2>\n<p>  \u0420\u0430\u043d\u0435\u0435 \u043c\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0432 <code>UserController<\/code>, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043b\u0430\u0433 <code>authorize_user<\/code>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0431\u044b\u0441\u0442\u0440\u0435\u043d\u044c\u043a\u043e \u0441\u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c, \u0447\u0442\u043e \u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c. \u041c\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0438 \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438, \u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441\u043c\u043e\u0433\u0443\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b.<\/p>\n<p>  \u041f\u043e\u0434 \u0441\u0442\u0440\u043e\u0447\u043a\u043e\u0439 <code>scrub_params<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 <code>web\/controllers\/user_controller.ex<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code>plug :authorize_admin when action in [:new, :create] plug :authorize_user when action in [:edit, :update, :delete]<\/code><\/pre>\n<p>  \u0418 \u0432\u043d\u0438\u0437\u0443 \u0444\u0430\u0439\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432:<\/p>\n<pre><code>defp authorize_user(conn, _) do   user = get_session(conn, :current_user)   if user && (Integer.to_string(user.id) == conn.params[&quot;id&quot;] || Pxblog.RoleChecker.is_admin?(user)) do     conn   else     conn     |&gt; put_flash(:error, &quot;You are not authorized to modify that user!&quot;)     |&gt; redirect(to: page_path(conn, :index))     |&gt; halt()   end end  defp authorize_admin(conn, _) do   user = get_session(conn, :current_user)   if user && Pxblog.RoleChecker.is_admin?(user) do     conn   else     conn     |&gt; put_flash(:error, &quot;You are not authorized to create new users!&quot;)     |&gt; redirect(to: page_path(conn, :index))     |&gt; halt()   end end<\/code><\/pre>\n<p>  \u0412\u044b\u0437\u043e\u0432 <code>authorize_user<\/code> \u043f\u043e \u0441\u0443\u0442\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u0435\u043d \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b\u043e \u0432 <code>PostController<\/code> \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 <code>RoleChecker.is_admin?<\/code>.<\/p>\n<p>  \u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>authorize_admin<\/code> \u0435\u0449\u0451 \u043f\u0440\u043e\u0449\u0435. \u041c\u044b \u043b\u0438\u0448\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.<\/p>\n<p>  \u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0443 <code>test\/controllers\/user_controller_test.exs<\/code> \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043d\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u043b\u0438 \u043d\u043e\u0432\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f.<\/p>\n<p>  \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u0430 setup.<\/p>\n<pre><code>setup do   {:ok, user_role}     = TestHelper.create_role(%{name: &quot;user&quot;, admin: false})   {:ok, nonadmin_user} = TestHelper.create_user(user_role, %{email: &quot;nonadmin@test.com&quot;, username: &quot;nonadmin&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})    {:ok, admin_role}    = TestHelper.create_role(%{name: &quot;admin&quot;, admin: true})   {:ok, admin_user}    = TestHelper.create_user(admin_role, %{email: &quot;admin@test.com&quot;, username: &quot;admin&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})    {:ok, conn: build_conn(), admin_role: admin_role, user_role: user_role, nonadmin_user: nonadmin_user, admin_user: admin_user} end<\/code><\/pre>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e \u0440\u043e\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0440\u043e\u043b\u044c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430, \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u0435\u0440\u043d\u0438\u0442\u0435 \u0438\u0445. \u0422\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0438 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u043c. \u041d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>login_user<\/code> \u0438\u0437 <code>PostController<\/code>.<\/p>\n<pre><code>defp login_user(conn, user) do   post conn, session_path(conn, :create), user: %{username: user.username, password: user.password} end<\/code><\/pre>\n<p>  \u041c\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e <code>index<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442. \u041d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0436\u0435 \u0442\u0435\u0441\u0442 \u00abrenders form for new resources\u00bb (\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 <code>new<\/code>) \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0441\u044f. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043f\u0440\u0430\u0432\u0430 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430.<\/p>\n<p>  \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0442\u0435\u0441\u0442, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043a\u043e\u0434\u0443:<\/p>\n<pre><code>@tag admin: true test &quot;renders form for new resources&quot;, %{conn: conn, admin_user: admin_user} do   conn = conn     |&gt; login_user(admin_user)     |&gt; get(user_path(conn, :new))   assert html_response(conn, 200) =~ &quot;New user&quot; end<\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0442\u0440\u043e\u0447\u043a\u0443 <code>@tag admin: true<\/code> \u043d\u0430\u0434 \u044d\u0442\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u043e\u0433\u043e. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c:<\/p>\n<pre><code class=\"bash\">mix test --only admin<\/code><\/pre>\n<p>  \u0412 \u0432\u044b\u0432\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<pre><code class=\"bash\">1) test renders form for new resources (Pxblog.UserControllerTest)  test\/controllers\/user_controller_test.exs:26  ** (KeyError) key :role_id not found in: %{id: 348, username: \u201cadmin\u201d}  stacktrace:  (pxblog) web\/models\/role_checker.ex:6: Pxblog.RoleChecker.is_admin?\/1  (pxblog) web\/controllers\/user_controller.ex:84: Pxblog.UserController.authorize_admin\/2  (pxblog) web\/controllers\/user_controller.ex:1: Pxblog.UserController.phoenix_controller_pipeline\/2  (pxblog) lib\/phoenix\/router.ex:255: Pxblog.Router.dispatch\/2  (pxblog) web\/router.ex:1: Pxblog.Router.do_call\/2  (pxblog) lib\/pxblog\/endpoint.ex:1: Pxblog.Endpoint.phoenix_pipeline\/1  (pxblog) lib\/phoenix\/endpoint\/render_errors.ex:34: Pxblog.Endpoint.call\/2  (phoenix) lib\/phoenix\/test\/conn_test.ex:193: Phoenix.ConnTest.dispatch\/5  test\/controllers\/user_controller_test.exs:28<\/code><\/pre>\n<p>  \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0442\u0443\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u043f\u043e\u043b\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>RoleChecker.is_admin?<\/code>. \u0410 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u043e\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <code>current_user<\/code> \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>sign_in<\/code> \u043c\u043e\u0434\u0443\u043b\u044f <code>SessionController<\/code>.<\/p>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u043d\u0438\u043c \u0442\u0430\u043a\u0436\u0435 \u0438 <code>role_id<\/code>. \u042f \u0432\u043d\u0451\u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b <code>web\/controllers\/session_controller.ex<\/code> \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0438\u0436\u0435:<\/p>\n<pre><code>defp sign_in(user, password, conn) do   if checkpw(password, user.password_digest) do     conn     |&gt; put_session(:current_user, %{id: user.id, username: user.username, role_id: user.role_id})     |&gt; put_flash(:info, &quot;Sign in successful!&quot;)     |&gt; redirect(to: page_path(conn, :index))   else     failed_login(conn)   end end<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0435\u0449\u0451 \u0440\u0430\u0437 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0441 \u0442\u0435\u0433\u043e\u043c <code>admin<\/code>.<\/p>\n<pre><code class=\"bash\">$ mix test --only admin<\/code><\/pre>\n<p>  \u0421\u043d\u043e\u0432\u0430 \u0437\u0435\u043b\u0451\u043d\u044b\u0435! \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0439\u0442\u0438 \u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 new \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 <code>UserController<\/code>. \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0443 <code>test\/controllers\/user_controller_test.exs<\/code>:<\/p>\n<pre><code>@tag admin: true test &quot;redirects from new form when not admin&quot;, %{conn: conn, nonadmin_user: nonadmin_user} do   conn = login_user(conn, nonadmin_user)   conn = get conn, user_path(conn, :new)   assert get_flash(conn, :error) == &quot;You are not authorized to create new users!&quot;   assert redirected_to(conn) == page_path(conn, :index)   assert conn.halted end<\/code><\/pre>\n<p>  \u0418 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0434\u043b\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f <code>create<\/code>. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0442\u0435\u0441\u0442\u0443 \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432.<\/p>\n<pre><code>@tag admin: true test &quot;creates resource and redirects when data is valid&quot;, %{conn: conn, user_role: user_role, admin_user: admin_user} do   conn = login_user(conn, admin_user)   conn = post conn, user_path(conn, :create), user: valid_create_attrs(user_role)   assert redirected_to(conn) == user_path(conn, :index)   assert Repo.get_by(User, @valid_attrs) end  @tag admin: true test &quot;redirects from creating user when not admin&quot;, %{conn: conn, user_role: user_role, nonadmin_user: nonadmin_user} do   conn = login_user(conn, nonadmin_user)   conn = post conn, user_path(conn, :create), user: valid_create_attrs(user_role)   assert get_flash(conn, :error) == &quot;You are not authorized to create new users!&quot;   assert redirected_to(conn) == page_path(conn, :index)   assert conn.halted end  @tag admin: true test &quot;does not create resource and renders errors when data is invalid&quot;, %{conn: conn, admin_user: admin_user} do   conn = login_user(conn, admin_user)   conn = post conn, user_path(conn, :create), user: @invalid_attrs   assert html_response(conn, 200) =~ &quot;New user&quot; end<\/code><\/pre>\n<p>  \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 <code>show<\/code>, \u0442.\u043a. \u043c\u044b \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0435\u043c\u0443 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043d\u043e\u0432\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0442\u0430\u043a\u043e\u043c\u0443 \u0436\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0443 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u0444\u0430\u0439\u043b <code>user_controller_test.exs<\/code> \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u043e\u0445\u043e\u0436 \u043d\u0430:<\/p>\n<pre><code>defmodule Pxblog.UserControllerTest do   use Pxblog.ConnCase   alias Pxblog.User   alias Pxblog.TestHelper    @valid_create_attrs %{email: &quot;test@test.com&quot;, username: &quot;test&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;}   @valid_attrs %{email: &quot;test@test.com&quot;, username: &quot;test&quot;}   @invalid_attrs %{}    setup do     {:ok, user_role}     = TestHelper.create_role(%{name: &quot;user&quot;, admin: false})     {:ok, nonadmin_user} = TestHelper.create_user(user_role, %{email: &quot;nonadmin@test.com&quot;, username: &quot;nonadmin&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})  {:ok, admin_role}    = TestHelper.create_role(%{name: &quot;admin&quot;, admin: true})     {:ok, admin_user}    = TestHelper.create_user(admin_role, %{email: &quot;admin@test.com&quot;, username: &quot;admin&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})      {:ok, conn: build_conn(), admin_role: admin_role, user_role: user_role, nonadmin_user: nonadmin_user, admin_user: admin_user}   end    defp valid_create_attrs(role) do     Map.put(@valid_create_attrs, :role_id, role.id)   end    defp login_user(conn, user) do     post conn, session_path(conn, :create), user: %{username: user.username, password: user.password}   end    test &quot;lists all entries on index&quot;, %{conn: conn} do     conn = get conn, user_path(conn, :index)     assert html_response(conn, 200) =~ &quot;Listing users&quot;   end    @tag admin: true   test &quot;renders form for new resources&quot;, %{conn: conn, admin_user: admin_user} do     conn = login_user(conn, admin_user)     conn = get conn, user_path(conn, :new)     assert html_response(conn, 200) =~ &quot;New user&quot;   end    @tag admin: true   test &quot;redirects from new form when not admin&quot;, %{conn: conn, nonadmin_user: nonadmin_user} do     conn = login_user(conn, nonadmin_user)     conn = get conn, user_path(conn, :new)     assert get_flash(conn, :error) == &quot;You are not authorized to create new users!&quot;     assert redirected_to(conn) == page_path(conn, :index)     assert conn.halted   end    @tag admin: true   test &quot;creates resource and redirects when data is valid&quot;, %{conn: conn, user_role: user_role, admin_user: admin_user} do     conn = login_user(conn, admin_user)     conn = post conn, user_path(conn, :create), user: valid_create_attrs(user_role)     assert redirected_to(conn) == user_path(conn, :index)     assert Repo.get_by(User, @valid_attrs)   end    @tag admin: true   test &quot;redirects from creating user when not admin&quot;, %{conn: conn, user_role: user_role, nonadmin_user: nonadmin_user} do     conn = login_user(conn, nonadmin_user)     conn = post conn, user_path(conn, :create), user: valid_create_attrs(user_role)     assert get_flash(conn, :error) == &quot;You are not authorized to create new users!&quot;     assert redirected_to(conn) == page_path(conn, :index)     assert conn.halted   end    @tag admin: true   test &quot;does not create resource and renders errors when data is invalid&quot;, %{conn: conn, admin_user: admin_user} do     conn = login_user(conn, admin_user)     conn = post conn, user_path(conn, :create), user: @invalid_attrs     assert html_response(conn, 200) =~ &quot;New user&quot;   end    test &quot;shows chosen resource&quot;, %{conn: conn} do     user = Repo.insert! %User{}     conn = get conn, user_path(conn, :show, user)     assert html_response(conn, 200) =~ &quot;Show user&quot;   end    test &quot;renders page not found when id is nonexistent&quot;, %{conn: conn} do     assert_error_sent 404, fn -&gt;       get conn, user_path(conn, :show, -1)     end   end    @tag admin: true   test &quot;renders form for editing chosen resource when logged in as that user&quot;, %{conn: conn, nonadmin_user: nonadmin_user} do     conn = login_user(conn, nonadmin_user)     conn = get conn, user_path(conn, :edit, nonadmin_user)     assert html_response(conn, 200) =~ &quot;Edit user&quot;   end    @tag admin: true   test &quot;renders form for editing chosen resource when logged in as an admin&quot;, %{conn: conn, admin_user: admin_user, nonadmin_user: nonadmin_user} do     conn = login_user(conn, admin_user)     conn = get conn, user_path(conn, :edit, nonadmin_user)     assert html_response(conn, 200) =~ &quot;Edit user&quot;   end    @tag admin: true   test &quot;redirects away from editing when logged in as a different user&quot;, %{conn: conn, nonadmin_user: nonadmin_user, admin_user: admin_user} do     conn = login_user(conn, nonadmin_user)     conn = get conn, user_path(conn, :edit, admin_user)     assert get_flash(conn, :error) == &quot;You are not authorized to modify that user!&quot;     assert redirected_to(conn) == page_path(conn, :index)     assert conn.halted   end    @tag admin: true   test &quot;updates chosen resource and redirects when data is valid when logged in as that user&quot;, %{conn: conn, nonadmin_user: nonadmin_user} do     conn = login_user(conn, nonadmin_user)     conn = put conn, user_path(conn, :update, nonadmin_user), user: @valid_create_attrs     assert redirected_to(conn) == user_path(conn, :show, nonadmin_user)     assert Repo.get_by(User, @valid_attrs)   end    @tag admin: true   test &quot;updates chosen resource and redirects when data is valid when logged in as an admin&quot;, %{conn: conn, admin_user: admin_user} do     conn = login_user(conn, admin_user)     conn = put conn, user_path(conn, :update, admin_user), user: @valid_create_attrs     assert redirected_to(conn) == user_path(conn, :show, admin_user)     assert Repo.get_by(User, @valid_attrs)   end    @tag admin: true   test &quot;does not update chosen resource when logged in as different user&quot;, %{conn: conn, nonadmin_user: nonadmin_user, admin_user: admin_user} do     conn = login_user(conn, nonadmin_user)     conn = put conn, user_path(conn, :update, admin_user), user: @valid_create_attrs     assert get_flash(conn, :error) == &quot;You are not authorized to modify that user!&quot;     assert redirected_to(conn) == page_path(conn, :index)     assert conn.halted   end    @tag admin: true   test &quot;does not update chosen resource and renders errors when data is invalid&quot;, %{conn: conn, nonadmin_user: nonadmin_user} do     conn = login_user(conn, nonadmin_user)     conn = put conn, user_path(conn, :update, nonadmin_user), user: @invalid_attrs     assert html_response(conn, 200) =~ &quot;Edit user&quot;   end    @tag admin: true   test &quot;deletes chosen resource when logged in as that user&quot;, %{conn: conn, user_role: user_role} do     {:ok, user} = TestHelper.create_user(user_role, @valid_create_attrs)     conn =       login_user(conn, user)       |&gt; delete(user_path(conn, :delete, user))     assert redirected_to(conn) == user_path(conn, :index)     refute Repo.get(User, user.id)   end    @tag admin: true   test &quot;deletes chosen resource when logged in as an admin&quot;, %{conn: conn, user_role: user_role, admin_user: admin_user} do     {:ok, user} = TestHelper.create_user(user_role, @valid_create_attrs)     conn =       login_user(conn, admin_user)       |&gt; delete(user_path(conn, :delete, user))     assert redirected_to(conn) == user_path(conn, :index)     refute Repo.get(User, user.id)   end    @tag admin: true   test &quot;redirects away from deleting chosen resource when logged in as a different user&quot;, %{conn: conn, user_role: user_role, nonadmin_user: nonadmin_user} do     {:ok, user} = TestHelper.create_user(user_role, @valid_create_attrs)     conn =       login_user(conn, nonadmin_user)       |&gt; delete(user_path(conn, :delete, user))     assert get_flash(conn, :error) == &quot;You are not authorized to modify that user!&quot;     assert redirected_to(conn) == page_path(conn, :index)     assert conn.halted   end end<\/code><\/pre>\n<p>  \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0432\u0435\u0441\u044c \u043d\u0430\u0431\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412\u0441\u0435 \u043e\u043d\u0438 \u0441\u043d\u043e\u0432\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442!<\/p>\n<h2>\u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043f\u043e\u0441\u0442\u044b<\/h2>\n<p>  \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u043c\u044b \u0443\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0441 \u043d\u0438\u043c, \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0433\u043e\u0442\u043e\u0432\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0442\u043a\u0440\u043e\u0435\u043c \u0444\u0430\u0439\u043b <code>web\/controllers\/post_controller.ex<\/code> \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>authorize_user<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0442\u043e\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>RoleChecker.is_admin?<\/code>. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c, \u0442\u043e \u0434\u0430\u0434\u0438\u043c \u0435\u043c\u0443 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0441\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<pre><code>defp authorize_user(conn, _) do   user = get_session(conn, :current_user)   if user && (Integer.to_string(user.id) == conn.params[&quot;user_id&quot;] || Pxblog.RoleChecker.is_admin?(user)) do     conn   else     conn     |&gt; put_flash(:error, &quot;You are not authorized to modify that post!&quot;)     |&gt; redirect(to: page_path(conn, :index))     |&gt; halt()   end end<\/code><\/pre>\n<p>  \u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u043e\u0442\u043a\u0440\u043e\u0435\u043c \u0444\u0430\u0439\u043b <code>test\/controllers\/post_controller_test.exs<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0451 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043f\u0440\u0430\u0432\u0438\u043b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<pre><code>test &quot;redirects when trying to delete a post for a different user&quot;, %{conn: conn, role: role, post: post} do   {:ok, other_user} = TestHelper.create_user(role, %{email: &quot;test2@test.com&quot;, username: &quot;test2&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})   conn = delete conn, user_post_path(conn, :delete, other_user, post)   assert get_flash(conn, :error) == &quot;You are not authorized to modify that post!&quot;   assert redirected_to(conn) == page_path(conn, :index)   assert conn.halted end  test &quot;renders form for editing chosen resource when logged in as admin&quot;, %{conn: conn, user: user, post: post} do   {:ok, role}  = TestHelper.create_role(%{name: &quot;Admin&quot;, admin: true})   {:ok, admin} = TestHelper.create_user(role, %{username: &quot;admin&quot;, email: &quot;admin@test.com&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})   conn =     login_user(conn, admin)     |&gt; get(user_post_path(conn, :edit, user, post))   assert html_response(conn, 200) =~ &quot;Edit post&quot; end  test &quot;updates chosen resource and redirects when data is valid when logged in as admin&quot;, %{conn: conn, user: user, post: post} do   {:ok, role}  = TestHelper.create_role(%{name: &quot;Admin&quot;, admin: true})   {:ok, admin} = TestHelper.create_user(role, %{username: &quot;admin&quot;, email: &quot;admin@test.com&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})   conn =     login_user(conn, admin)     |&gt; put(user_post_path(conn, :update, user, post), post: @valid_attrs)   assert redirected_to(conn) == user_post_path(conn, :show, user, post)   assert Repo.get_by(Post, @valid_attrs) end  test &quot;does not update chosen resource and renders errors when data is invalid when logged in as admin&quot;, %{conn: conn, user: user, post: post} do   {:ok, role}  = TestHelper.create_role(%{name: &quot;Admin&quot;, admin: true})   {:ok, admin} = TestHelper.create_user(role, %{username: &quot;admin&quot;, email: &quot;admin@test.com&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})   conn =     login_user(conn, admin)     |&gt; put(user_post_path(conn, :update, user, post), post: %{&quot;body&quot; =&gt; nil})   assert html_response(conn, 200) =~ &quot;Edit post&quot; end  test &quot;deletes chosen resource when logged in as admin&quot;, %{conn: conn, user: user, post: post} do   {:ok, role}  = TestHelper.create_role(%{name: &quot;Admin&quot;, admin: true})   {:ok, admin} = TestHelper.create_user(role, %{username: &quot;admin&quot;, email: &quot;admin@test.com&quot;, password: &quot;test&quot;, password_confirmation: &quot;test&quot;})   conn =     login_user(conn, admin)     |&gt; delete(user_post_path(conn, :delete, user, post))   assert redirected_to(conn) == user_post_path(conn, :index, user)   refute Repo.get(Post, post.id) end<\/code><\/pre>\n<p>  \u041f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u0448 \u0431\u043b\u043e\u0433\u043e\u0432\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a \u0432 \u0446\u0435\u043b\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u0435\u0437 \u0441\u0431\u043e\u0435\u0432, \u043d\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0433\u043e\u0432. \u041c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043d\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043f\u043e \u043e\u043f\u043b\u043e\u0448\u043d\u043e\u0441\u0442\u0438. \u043b\u0438\u0431\u043e \u043c\u044b \u0447\u0442\u043e-\u0442\u043e \u0437\u0430\u0431\u044b\u043b\u0438 \u043f\u043e \u043f\u0443\u0442\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u044f\u0432\u0438\u043c \u0438 \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u043c \u0438\u0445. \u0422\u0430\u043a\u0436\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u043c \u0432\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0435\u0433\u043e \u0447\u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e.<\/p>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u044b\u0434\u0430\u0451\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u043e\u0431 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0440\u043e\u043b\u044f\u0445<\/h2>\n<p>  \u041d\u0430 \u044d\u0442\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 <b>nolotus<\/b> \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <b>Pxblog<\/b> (<a href=\"https:\/\/github.com\/Diamond\/pxblog).\">https:\/\/github.com\/Diamond\/pxblog).<\/a> \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0442\u0435\u0431\u0435! <\/p>\n<p>  \u0412 \u0432\u0435\u0442\u043a\u0435 <code>part_3<\/code> \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043e\u0448\u0438\u0431\u043a\u0435 \u0438\u0437-\u0437\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u0440\u043e\u043b\u0438 (\u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 <code>role_id<\/code> \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f). \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u0437\u0443\u0447\u0438\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u043d\u0430\u0447\u043d\u0451\u043c \u0435\u0451 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u0439\u0434\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/users\/new<\/code>, \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0438 \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/326\/45a\/6a9\/32645a6a9bf04e19a195d12d4d5040db.png\"\/><br \/>  \u041a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u044b \u0442\u0440\u0435\u0431\u0443\u0435\u043c \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d\u0438, \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b, \u043f\u0430\u0440\u043e\u043b\u044f, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u043e\u043b\u044f. \u041d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u0440\u043e\u043b\u0438. \u0422\u0435\u043f\u0435\u0440\u044c, \u0437\u043d\u0430\u044f \u043e\u0431 \u044d\u0442\u043e\u043c, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0440\u043e\u043b\u0435\u0439 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0432 \u0444\u043e\u0440\u043c\u0435.<\/p>\n<p>  \u041e\u043d \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0438\u0437 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439: <code>new, create, edit \u0438 update<\/code>. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 <code>alias Pxblog.Role<\/code> \u043d\u0430\u0432\u0435\u0440\u0445 UserController (\u0444\u0430\u0439\u043b <code>web\/controllers\/user_controller.ex<\/code>) \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043a\u0430 \u0435\u0449\u0451 \u0442\u0430\u043c \u043d\u0435\u0442. \u0417\u0430\u0442\u0435\u043c \u0432\u043d\u0435\u0441\u0451\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043e \u0432\u0441\u0435 \u0440\u0430\u043d\u0435\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<pre><code>def new(conn, _params) do   roles = Repo.all(Role)   changeset = User.changeset(%User{})   render(conn, &quot;new.html&quot;, changeset: changeset, roles: roles) end def edit(conn, %{&quot;id&quot; =&gt; id}) do   roles = Repo.all(Role)   user = Repo.get!(User, id)   changeset = User.changeset(user)   render(conn, &quot;edit.html&quot;, user: user, changeset: changeset, roles: roles) end def create(conn, %{&quot;user&quot; =&gt; user_params}) do   roles = Repo.all(Role)   changeset = User.changeset(%User{}, user_params)    case Repo.insert(changeset) do     {:ok, _user} -&gt;       conn       |&gt; put_flash(:info, &quot;User created successfully.&quot;)       |&gt; redirect(to: user_path(conn, :index))     {:error, changeset} -&gt;       render(conn, &quot;new.html&quot;, changeset: changeset, roles: roles)   end end def update(conn, %{&quot;id&quot; =&gt; id, &quot;user&quot; =&gt; user_params}) do   roles = Repo.all(Role)   user = Repo.get!(User, id)   changeset = User.changeset(user, user_params)    case Repo.update(changeset) do     {:ok, user} -&gt;       conn       |&gt; put_flash(:info, &quot;User updated successfully.&quot;)       |&gt; redirect(to: user_path(conn, :show, user))     {:error, changeset} -&gt;       render(conn, &quot;edit.html&quot;, user: user, changeset: changeset, roles: roles)   end end<\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u043c\u044b \u0432\u044b\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u0440\u043e\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Repo.all(Role)<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0438\u0445 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a <code>assigns<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044e (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438).<\/p>\n<p>  \u041d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0444\u043e\u0440\u043c \u0438\u0437 <code>Phoenix.Html<\/code>. \u0422\u0430\u043a \u0447\u0442\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f <a href=\"https:\/\/hexdocs.pm\/phoenix_html\/Phoenix.HTML.Form.html#select\/4\">\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>:<\/p>\n<pre><code>select(form, field, values, opts \\\\ [])   Generates a select tag with the given values.<\/code><\/pre>\n<p>  \u0412\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u043e\u0436\u0438\u0434\u0430\u044e\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 <code>values<\/code> \u043b\u0438\u0431\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a (\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>[value, value, value]<\/code>), \u043b\u0438\u0431\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432 (\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>[displayed: value, displayed: value]<\/code>). \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0440\u043e\u043b\u0435\u0439 \u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u044d\u0442\u0438\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0440\u043e\u043b\u0438 \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0444\u043e\u0440\u043c\u044b. \u041c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043b\u0435\u043f\u043e \u043a\u0438\u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>@roles<\/code> \u0432\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0430 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043d\u0438 \u043f\u043e\u0434 \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432. \u0422\u0430\u043a \u0447\u0442\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u043e <code>View<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442 \u043d\u0430\u0448\u0443 \u0437\u0430\u0434\u0430\u0447\u0443.<\/p>\n<pre><code>defmodule Pxblog.UserView do   use Pxblog.Web, :view    def roles_for_select(roles) do     roles     |&gt; Enum.map(&[&quot;#{&1.name}&quot;: &1.id])     |&gt; List.flatten   end end<\/code><\/pre>\n<p>  \u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>roles_for_select<\/code>, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0443\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u0440\u043e\u043b\u0435\u0439. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0442\u043e \u0436\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0440\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435:<\/p>\n<pre><code>Enum.map(&[&quot;#{&1.name}&quot;: &1.id])<\/code><\/pre>\n<p>  \u0421\u043d\u043e\u0432\u0430 \u043d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e <code>&\/&1<\/code> \u2014 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043f\u043e\u043b\u043d\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435 \u0442\u0430\u043a:<\/p>\n<pre><code>Enum.map(roles, fn role -&gt; [&quot;#{role.name}&quot;: role.id] end)<\/code><\/pre>\n<p>  \u041c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e <code>map<\/code>, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 \u0431\u043e\u043b\u0435\u0435 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432, \u0433\u0434\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u043b\u0438 \u2014 \u043a\u043b\u044e\u0447, \u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0440\u043e\u043b\u0438 \u2014 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0434\u0430\u043d\u043e \u043d\u0435\u043a\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u043e\u043b\u0435\u0439:<\/p>\n<pre><code>roles = [%Role{name: &quot;Admin Role&quot;, id: 1}, %Role{name: &quot;User Role&quot;, id: 2}]<\/code><\/pre>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 map \u0432\u0435\u0440\u043d\u0443\u043b \u0431\u044b \u0442\u0430\u043a\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a:<\/p>\n<pre><code>[[&quot;Admin Role&quot;: 1], [&quot;User Role&quot;: 2]]<\/code><\/pre>\n<p>  \u041a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0442\u0435\u043c \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>List.flatten<\/code>, \u0443\u0431\u0438\u0440\u0430\u044e\u0449\u0443\u044e \u043b\u0438\u0448\u043d\u044e\u044e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u044c. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0430\u0448 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<pre><code>[&quot;Admin Role&quot;: 1, &quot;User Role&quot;: 2]<\/code><\/pre>\n<p>  \u0422\u0430\u043a \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430! \u041f\u043e\u043a\u0430 \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u0445\u043b\u043e\u043f\u0430\u0442\u044c \u0441\u0435\u0431\u044f \u043f\u043e \u043f\u043b\u0435\u0447\u0443, \u0432\u0435\u0434\u044c \u043d\u0430\u043c \u0432\u0441\u0451 \u0435\u0449\u0451 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 <code>web\/templates\/user\/new.html.eex<\/code>:<\/p>\n<pre><code>&lt;h2&gt;New user&lt;\/h2&gt;  &lt;%= render &quot;form.html&quot;, changeset: @changeset,                         action: user_path(@conn, :create),                         roles: @roles %&gt;  &lt;%= link &quot;Back&quot;, to: user_path(@conn, :index) %&gt;<\/code><\/pre>\n<p>  \u0418 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>web\/templates\/user\/edit.html.eex<\/code>: <\/p>\n<pre><code> &lt;h2&gt;Edit user&lt;\/h2&gt; &lt;%= render &quot;form.html&quot;, changeset: @changeset,                         action: user_path(@conn, :update, @user),                         roles: @roles %&gt; &lt;%= link &quot;Back&quot;, to: user_path(@conn, :index) %&gt;  <\/code><\/pre>\n<p>  \u041d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u044f \u0434\u0443\u043c\u0430\u044e \u0432\u044b \u043d\u0435 \u043e\u0442\u043a\u0430\u0436\u0435\u0442\u0435\u0441\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448\u0443 \u043d\u043e\u0432\u0443\u044e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u0444\u0430\u0439\u043b <code>web\/templates\/user\/form.html.eex<\/code>. \u041a\u0430\u043a \u0438\u0442\u043e\u0433, \u0432 \u0444\u043e\u0440\u043c\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0440\u043e\u043b\u0438. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0434\u043e \u043a\u043d\u043e\u043f\u043a\u0438 <b>Submit<\/b>:<\/p>\n<pre><code>&lt;div class=&quot;form-group&quot;&gt;   &lt;%= label f, :role_id, &quot;Role&quot;, class: &quot;control-label&quot; %&gt;   &lt;%= select f, :role_id, roles_for_select(@roles), class: &quot;form-control&quot; %&gt;   &lt;%= error_tag f, :role_id %&gt; &lt;\/div&gt;<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u0442\u044c \u0440\u043e\u043b\u044c \u044d\u0442\u043e\u043c\u0443 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0443! \u041e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0431\u0430\u0433!<\/p>\n<h2>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u043e\u0434\u0440\u044f\u0434 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u0442 \u0438\u0445<\/h2>\n<p>  \u041f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441, \u0435\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043c \u043d\u0430\u0448\u0438 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0434\u0443\u0431\u043b\u0438, \u0447\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0430\u0440\u0443 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <code>find_or_create<\/code>:<\/p>\n<pre><code>alias Pxblog.Repo alias Pxblog.Role alias Pxblog.User import Ecto.Query, only: [from: 2]  find_or_create_role = fn role_name, admin -&gt;   case Repo.all(from r in Role, where: r.name == ^role_name and r.admin == ^admin) do     [] -&gt;       %Role{}       |&gt; Role.changeset(%{name: role_name, admin: admin})       |&gt; Repo.insert!()     _ -&gt;       IO.puts &quot;Role: #{role_name} already exists, skipping&quot;   end end  find_or_create_user = fn username, email, role -&gt;   case Repo.all(from u in User, where: u.username == ^username and u.email == ^email) do     [] -&gt;       %User{}       |&gt; User.changeset(%{username: username, email: email, password: &quot;test&quot;, password_confirmation: &quot;test&quot;, role_id: role.id})       |&gt; Repo.insert!()     _ -&gt;       IO.puts &quot;User: #{username} already exists, skipping&quot;   end end  _user_role  = find_or_create_role.(&quot;User Role&quot;, false) admin_role  = find_or_create_role.(&quot;Admin Role&quot;, true) _admin_user = find_or_create_user.(&quot;admin&quot;, &quot;admin@test.com&quot;, admin_role)<\/code><\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0441\u0435\u0432\u0434\u043e\u043d\u0438\u043c\u0430 <code>Repo<\/code>, <code>Role<\/code> \u0438 <code>User<\/code>. \u041c\u044b \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>from<\/code> \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f <code>Ecto.Query<\/code>, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0417\u0430\u0442\u0435\u043c \u0432\u0437\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u043d\u0430 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>find_or_create_role<\/code>. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0430\u043c\u0430 \u043f\u043e \u0441\u0435\u0431\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0444\u043b\u0430\u0433 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p>  \u041e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u0438\u0445 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u044f\u0445 \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Repo.all<\/code> (\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0437\u043d\u0430\u043a <b>^<\/b>, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0437\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u044f <code>where<\/code>, \u0442.\u043a. \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u043c). \u0418 \u043a\u0438\u0434\u0430\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 case. \u0415\u0441\u043b\u0438 <code>Repo.all<\/code> \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043d\u0430\u0448\u0451\u043b, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u043e\u043b\u044c. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u043c, \u0447\u0442\u043e \u0440\u043e\u043b\u044c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>find_or_create_user<\/code> \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0438.<\/p>\n<p>  \u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u0438\u0437 \u044d\u0442\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0434\u043b\u044f \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0442\u043e\u0447\u043a\u0443 \u043c\u0435\u0436\u0434\u0443 \u0438\u0445 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438!). \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0440\u043e\u043b\u044c. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043d\u0435 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u044f\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 <code>admin_role<\/code> \u0437\u043d\u0430\u043a\u043e\u043c \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f. \u041f\u043e\u0437\u0436\u0435 \u043c\u044b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432 \u0445\u043e\u0434 <code>user_role<\/code> \u0438\u043b\u0438 <code>admin_user<\/code> \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u043f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0432 \u043f\u043e\u043a\u043e\u0435, \u043e\u0431\u0440\u0430\u0442\u0438\u0432\u0448\u0438\u0441\u044c \u043a \u0437\u043d\u0430\u043a\u0443 \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0444\u0430\u0439\u043b\u0443 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043e\u043f\u0440\u044f\u0442\u043d\u044b\u043c \u0438 \u0447\u0438\u0441\u0442\u044b\u043c. \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0451 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"bash\">$ mix run priv\/repo\/seeds.exs [debug] SELECT r0.\u201did\u201d, r0.\u201dname\u201d, r0.\u201dadmin\u201d, r0.\u201dinserted_at\u201d, r0.\u201dupdated_at\u201d FROM \u201croles\u201d AS r0 WHERE ((r0.\u201dname\u201d = $1) AND (r0.\u201dadmin\u201d = $2)) [\u201cUser Role\u201d, false] OK query=81.7ms queue=2.8ms [debug] BEGIN [] OK query=0.2ms [debug] INSERT INTO \u201croles\u201d (\u201cadmin\u201d, \u201cinserted_at\u201d, \u201cname\u201d, \u201cupdated_at\u201d) VALUES ($1, $2, $3, $4) RETURNING \u201cid\u201d [false, {{2015, 11, 6}, {19, 35, 49, 0}}, \u201cUser Role\u201d, {{2015, 11, 6}, {19, 35, 49, 0}}] OK query=0.8ms [debug] COMMIT [] OK query=0.4ms [debug] SELECT r0.\u201did\u201d, r0.\u201dname\u201d, r0.\u201dadmin\u201d, r0.\u201dinserted_at\u201d, r0.\u201dupdated_at\u201d FROM \u201croles\u201d AS r0 WHERE ((r0.\u201dname\u201d = $1) AND (r0.\u201dadmin\u201d = $2)) [\u201cAdmin Role\u201d, true] OK query=0.4ms [debug] BEGIN [] OK query=0.2ms [debug] INSERT INTO \u201croles\u201d (\u201cadmin\u201d, \u201cinserted_at\u201d, \u201cname\u201d, \u201cupdated_at\u201d) VALUES ($1, $2, $3, $4) RETURNING \u201cid\u201d [true, {{2015, 11, 6}, {19, 35, 49, 0}}, \u201cAdmin Role\u201d, {{2015, 11, 6}, {19, 35, 49, 0}}] OK query=0.4ms [debug] COMMIT [] OK query=0.3ms [debug] SELECT u0.\u201did\u201d, u0.\u201dusername\u201d, u0.\u201demail\u201d, u0.\u201dpassword_digest\u201d, u0.\u201drole_id\u201d, u0.\u201dinserted_at\u201d, u0.\u201dupdated_at\u201d FROM \u201cusers\u201d AS u0 WHERE ((u0.\u201dusername\u201d = $1) AND (u0.\u201demail\u201d = $2)) [\u201cadmin\u201d, \u201cadmin@test.com\u201d] OK query=0.7ms [debug] BEGIN [] OK query=0.3ms [debug] INSERT INTO \u201cusers\u201d (\u201cemail\u201d, \u201cinserted_at\u201d, \u201cpassword_digest\u201d, \u201crole_id\u201d, \u201cupdated_at\u201d, \u201cusername\u201d) VALUES ($1, $2, $3, $4, $5, $6) RETURNING \u201cid\u201d [\u201cadmin@test.com\u201d, {{2015, 11, 6}, {19, 35, 49, 0}}, \u201c$2b$12$.MuPBUVe\/7\/9HSOsccJYUOAD5IKEB77Pgz2oTJ\/UvTvWYwAGn\/L.i\u201d, 2, {{2015, 11, 6}, {19, 35, 49, 0}}, \u201cadmin\u201d] OK query=1.2ms [debug] COMMIT [] OK query=1.1ms<\/code><\/pre>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0438\u0445 \u0432\u043f\u0435\u0440\u0432\u044b\u0435, \u0442\u043e \u0432\u0438\u0434\u0438\u043c \u043f\u0430\u0447\u043a\u0443 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439 <code>INSERT<\/code>. \u041f\u043e\u0442\u0440\u044f\u0441\u0430\u044e\u0449\u0435! \u0427\u0442\u043e\u0431\u044b \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c\u0438, \u0447\u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u043d\u0430\u0434\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0438\u0445 \u0435\u0449\u0451 \u0440\u0430\u0437 \u0438 \u0443\u0431\u0435\u0434\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0432\u0441\u0442\u0430\u0432\u043e\u043a:<\/p>\n<pre><code class=\"bash\">$ mix run priv\/repo\/seeds.exs Role: User Role already exists, skipping [debug] SELECT r0.\u201did\u201d, r0.\u201dname\u201d, r0.\u201dadmin\u201d, r0.\u201dinserted_at\u201d, r0.\u201dupdated_at\u201d FROM \u201croles\u201d AS r0 WHERE ((r0.\u201dname\u201d = $1) AND (r0.\u201dadmin\u201d = $2)) [\u201cUser Role\u201d, false] OK query=104.8ms queue=3.6ms Role: Admin Role already exists, skipping [debug] SELECT r0.\u201did\u201d, r0.\u201dname\u201d, r0.\u201dadmin\u201d, r0.\u201dinserted_at\u201d, r0.\u201dupdated_at\u201d FROM \u201croles\u201d AS r0 WHERE ((r0.\u201dname\u201d = $1) AND (r0.\u201dadmin\u201d = $2)) [\u201cAdmin Role\u201d, true] OK query=0.6ms User: admin already exists, skipping [debug] SELECT u0.\u201did\u201d, u0.\u201dusername\u201d, u0.\u201demail\u201d, u0.\u201dpassword_digest\u201d, u0.\u201drole_id\u201d, u0.\u201dinserted_at\u201d, u0.\u201dupdated_at\u201d FROM \u201cusers\u201d AS u0 WHERE ((u0.\u201dusername\u201d = $1) AND (u0.\u201demail\u201d = $2)) [\u201cadmin\u201d, \u201cadmin@test.com\u201d] OK query=0.8ms<\/code><\/pre>\n<p>  \u0412\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u043e! \u0412\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0430\u0434\u0451\u0436\u043d\u043e! \u041f\u043b\u044e\u0441 \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u0442 \u0442\u043e\u0433\u043e \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u044f, \u0447\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043d\u0430\u0448\u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f <code>Ecto<\/code>!<\/p>\n<h2>\u041e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u043e \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442, \u0432\u044b \u0441\u0431\u0440\u043e\u0441\u0438\u0442\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043e\u0448\u0438\u0431\u043a\u0443, \u0433\u043b\u0430\u0441\u044f\u0449\u0443\u044e <i>\u00ab\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\u00bb<\/i>. \u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 (\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439) \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>test\/support\/test_helper.ex<\/code> \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>create_user<\/code>:<\/p>\n<pre><code>def create_user(role, %{email: email, username: username, password: password, password_confirmation: password_confirmation}) do   if user = Repo.get_by(User, username: username) do     Repo.delete(user)   end   role   |&gt; build_assoc(:users)   |&gt; User.changeset(%{email: email, username: username, password: password, password_confirmation: password_confirmation})   |&gt; Repo.insert end<\/code><\/pre>\n<h2>\u041a \u0447\u0435\u043c\u0443 \u043c\u044b \u043f\u0440\u0438\u0448\u043b\u0438?<\/h2>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0435\u043b\u0451\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043f\u043e\u0441\u0442\u044b \u0438 \u0440\u043e\u043b\u0438. \u041c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0439, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u043e\u0441\u0442\u043e\u0432. \u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u043f\u043e\u0441\u0442\u0430\u0445 \u043c\u044b \u043f\u043e\u0441\u0432\u044f\u0442\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u043d\u043e\u0432\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043d\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0431\u043b\u043e\u0433\u043e\u0432\u043e\u043c\u0443 \u0434\u0432\u0438\u0436\u043a\u0443!<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0442 \u0412\u0443\u043d\u0448\u0435\u0439<\/h2>\n<p>  \u0421 \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0435\u0439 \u043d\u0430\u0441 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0441\u0451 \u0431\u043e\u043b\u044c\u0448\u0435, \u0430 \u044d\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0440\u0430\u0434\u043e\u0432\u0430\u0442\u044c! \u0414\u0440\u0443\u0437\u044c\u044f, \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441 \u043a \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0443 \u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u043d\u043e\u0435 \u0434\u043e\u0432\u0435\u0440\u0438\u0435. \u0421\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u0435\u0433\u043e \u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430\u0442\u044c \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432 \u043d\u0435\u0434\u0435\u043b\u044e \u0432\u044b\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0441\u0451 \u0435\u0449\u0451 \u043d\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b\u0438\u0441\u044c \u043d\u0430 <a href=\"https:\/\/wunsh.ru\/?utm_source=habrahabr&amp;utm_medium=content&amp;utm_campaign=blog-phoenix-4\">\u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u0443\u044e \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0443 \u043e\u0431 Elixir<\/a>, \u0442\u043e \u043d\u0435 \u0442\u0435\u0440\u044f\u0439\u0442\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0443\u0436\u0435 \u0437\u0430\u0432\u0442\u0440\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043d\u043e\u0432\u0443\u044e \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e! \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u043d\u043e\u0447\u0438 \u043d\u0430\u043f\u0440\u043e\u043b\u0451\u0442, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0432\u0430\u0441.<\/p>\n<p>  \u0415\u0449\u0451 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e, \u0447\u0442\u043e \u043c\u044b \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c <a href=\"https:\/\/wunsh.ru\/first_contest.html?utm_source=habr&amp;utm_medium=content&amp;utm_campaign=first_contest\">\u043a\u043e\u043d\u043a\u0443\u0440\u0441 \u0441 \u043d\u043e\u0432\u0435\u043d\u044c\u043a\u043e\u0439 \u0445\u0440\u0443\u0441\u0442\u044f\u0449\u0435\u0439 \u043a\u043d\u0438\u0433\u043e\u0439 Programming Elixir \u043e\u0442 \u0414\u0435\u0439\u0432\u0430 \u0422\u043e\u043c\u0430\u0441\u0430<\/a> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u0437\u0430. \u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0439\u0442\u0435 \u0443\u0447\u0430\u0441\u0442\u0438\u0435, \u0432\u044b\u0438\u0433\u0440\u0430\u0442\u044c \u043d\u0435 \u0442\u0430\u043a \u0441\u043b\u043e\u0436\u043d\u043e!<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043b\u044e\u0441\u044b \u0438 \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0434\u0440\u0443\u0437\u044c\u044f\u043c, \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c. \u041b\u0438\u0431\u043e \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u043d\u0430\u0448\u0430 \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0412\u0435\u0434\u044c \u0447\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043c\u0430\u0441\u0441\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u0441\u0430\u0439\u0442\u0430, \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u043e \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u042d\u043b\u0438\u043a\u0441\u0438\u0440\u0435.<\/p>\n<p>  \u0414\u0440\u0443\u0433\u0438\u0435 \u0447\u0430\u0441\u0442\u0438:  <\/p>\n<ol>\n<li><a href=\"https:\/\/habrahabr.ru\/post\/311088\/\">\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/post\/313482\/\">\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/a><\/li>\n<li><a href=\"https:\/\/habrahabr.ru\/post\/315252\/\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u043b\u0435\u0439<\/a><\/li>\n<li>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0440\u043e\u043b\u0435\u0439 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445<\/li>\n<li>\u0421\u043a\u043e\u0440\u043e&#8230;<\/li>\n<\/ol>\n<p>  \u0423\u0441\u043f\u0435\u0445\u043e\u0432 \u0432 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0438, \u043e\u0441\u0442\u0430\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u0441 \u043d\u0430\u043c\u0438!<br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habrahabr.ru\/post\/316368\/\"> https:\/\/habrahabr.ru\/post\/316368\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/81c\/359\/9c0\/81c3599c01a1461aa1ecf172a495a750.png\"\/><\/p>\n<p>  \u041e\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0447\u0438\u043a\u0430: \u00ab<i>Elixir \u0438 Phoenix \u2014 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0443\u0434\u0430 \u0434\u0432\u0438\u0436\u0435\u0442\u0441\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430. \u0423\u0436\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0421\u0430\u0439\u0442\u044b \u0441 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c\u044e, \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0435 \u0438\u0433\u0440\u044b, \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u2014 \u0442\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0441\u043e\u0441\u043b\u0443\u0436\u0430\u0442 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u0441\u043b\u0443\u0436\u0431\u0443. \u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0435\u0440\u0438\u0438 \u0438\u0437 11 \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 \u0424\u0435\u043d\u0438\u043a\u0441 \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b \u0442\u0430\u043a\u043e\u0439 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0449\u0438, \u043a\u0430\u043a \u0431\u043b\u043e\u0433\u043e\u0432\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a. \u041d\u043e \u043d\u0435 \u0441\u043f\u0435\u0448\u0438\u0442\u0435 \u043a\u0443\u043a\u0441\u0438\u0442\u044c\u0441\u044f, \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e\u0431\u0443\u0434\u044f\u0442 \u0432\u0430\u0441 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u042d\u043b\u0438\u043a\u0441\u0438\u0440 \u043b\u0438\u0431\u043e \u0441\u0442\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0440\u0430\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u043e\u043b\u0435\u0439. \u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u2014 \u0437\u0434\u0435\u0441\u044c \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0443\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0430\u043c, \u0430 \u0442\u0435\u0441\u0442\u044b \u2014 \u044d\u0442\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u043e!<\/i><\/p>\n<p>  \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043e \u043d\u0430:<\/p>\n<ul>\n<li><b>Elixir<\/b>: v1.3.1<\/li>\n<li><b>Phoenix<\/b>: v1.2.0<\/li>\n<li><b>Ecto<\/b>: v2.0.2<\/li>\n<li><b>Comeonin<\/b>: v2.5.2<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>\u0413\u0434\u0435 \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c<\/h2>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0440\u0430\u0441\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0441 \u0432\u0430\u043c\u0438 \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u0440\u043e\u043b\u0438 \u0432\u043d\u0443\u0442\u0440\u044c \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0436\u0438\u0437\u043d\u044c. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0440\u043e\u043b\u044f\u0445 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435.<\/p>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u043e\u043b\u0435\u0439<\/h2>\n<p>  \u041f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0441\u0442\u0430\u043d\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043f\u0440\u0430\u0432 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>web\/models\/role_checker.ex<\/code> \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c:  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-281688","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281688","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=281688"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281688\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=281688"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=281688"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=281688"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}