# List からの値取り出し
list = [1,2,3,4]
IO.inspect(Enum.at(list, 0))
IO.inspect(Enum.at(list, 1))
# Map からの値取り出し
map = %{a: 1, b: 2, c: 3, d: 4}
IO.inspect(Map.get(map, :a))
IO.inspect(Map.get(map, :b))
# Tuple からの値取り出し
tuple = {1, 2, 3, 4}
IO.inspect(elem(tuple, 0))
IO.inspect(elem(tuple, 1))
Category: ‘Elixir’
Elixir 値取得方法
Phoenix Server をバックグラウンドにて動作させる方法
$ elixir --erl "-detached" -S mix phx.server
Phoenix – React 連携
Phoenix Project 作成
$ mix phx.new ProjectName --app project_name --no-ecto
npm モジュールインストール
$ cd ProjectName/assets/node_modules/
$ npm install --save @babel/preset-react
$ npm install --save @babel/polyfill
$ npm install --save react react-dom redux react-redux
$ npm install --save react-router-dom
$ npm install --save connected-react-router history
$ npm install --save redux-thunk
$ npm install --save axios
$ npm install --save redux-form react-hook-form
$ npm install --save react-bootstrap
$ npm install --save history
$ npm install redux-saga --save
.babelrc 設定
assets/.babelrc
{
"presets": [
"@babel/preset-env",
"@babel/react"
]
}
エントリポイント(index.js)の変更
$mv assets/js/app.js assets/js/index.js
index.js
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<div>
Hello React!!
</div>,
document.getElementById('root')
);
webpack.config.js
entry: {
'./js/index.js': glob.sync('./vendor/**/*.js').concat(['./js/index.js'])
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, '../priv/static/js')
},
index.eex の変更
lib/project_name_web/templates/page/index.eex
<section class="row">
<article class="column">
<div id="root"></div>
</article>
</section>
index.jsパスの変更
lib/project_name_web/templates/layout/app.eex
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/index.js") %>"></script>
Elixir Timex のフォーマット
Timex を使用した時の、現在時間フォーマット。
Timex.format!(Timex.now("Asia/Tokyo"), "%Y/%m/%d %H:%M:%S", :strftime)
Elixir で md5 暗号化
特に必要はなかったのだが、ちょっとお試しで書いてみた。
ちなみに、erlang20.0 で、crypto:md5/1 は廃止されているようなので、crypto:hash/2 を使用するようだ。
crypto:md5/1 will fail, since it was removed in 20.0; use crypto:hash/2
また、そのままだとバイナリで表示されるので、Base.encode16 で文字列化すること。
iex(1)> Crypto.convert_md5 <<254, 97, 249, 200, 73, 189, 91, 193, 23, 19, 37, 187, 163, 17, 159, 144>>
defmodule Crypto do def convert_md5 do :crypto.hash(:md5, "Whoocus") # :crypto.md5("Whoocus") |> Base.encode16(case: :lower) end end
iex(2)> Crypto.convert_md5 "fe61f9c849bd5bc1171325bba3119f90"
Phoenix でメールを送信する
まずは、メール用のプロジェクトの依存ライブラリである Bumboo をインストールする。
■ mix.exs
def application do [ mod: {MyApp.Application, []}, extra_applications: [:logger, :runtime_tools, :bamboo] ] end defp deps do [ {:phoenix, "~> 1.3.2"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.2"}, {:mariaex, ">= 0.0.0"}, {:phoenix_html, "~> 2.10"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:cowboy, "~> 1.0"}, {:bamboo, "~> 0.7"}, {:bamboo_smtp, "~> 1.2.1"} ] end
mix deps.get で追加した依存ライブラリをインストールする。
$ mix deps.get
プロジェクト設定ファイルに、メール設定情報を追記する。ここではSMTPサーバとしてGmailアカウントを使う。
■ config/config.exs
config :myapp, MyApp.Mailer, adapter: Bamboo.SMTPAdapter, server: "smtp.gmail.com", port: 587, username: "my@gmail.com", password: "password", tls: :if_available, # can be `:always` or `:never` ssl: false, # can be `true` retries: 1
メーラーモジュールを作成する。
■ lib/myapp/mailer.ex
defmodule MyApp.Mailer do use Bamboo.Mailer, otp_app: :myapp end
メールモジュールを作成する。
■ lib/myapp/email.ex
defmodule MyApp.Email do use Bamboo.Phoenix, view: MyApp.EmailView def hello_email(email) do new_email |> to(email) |> from("my@gmail.com") |> subject("Welcome!") |> text_body("Welcome to My App!!") end end
まずは、試しにコマンドラインからメールしてみる。
$ iex -S mix Interactive Elixir (1.6.5) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> MyApp.Email.hello_email("tajima@whoocus.com") |> MyApp.Mailer.deliver_now [debug] Sending email with Bamboo.SMTPAdapter: %Bamboo.Email{assigns: %{}, bcc: [], cc: [], from: {nil, "my@gmail.com"}, headers: %{}, html_body: nil, private: %{}, subject: "Welcome!", text_body: "Welcome to My App!!", to: [nil: "tajima@whoocus.com"]} %Bamboo.Email{ assigns: %{}, bcc: [], cc: [], from: {nil, "my@gmail.com"}, headers: %{}, html_body: nil, private: %{}, subject: "Welcome!", text_body: "Welcome to My App!!", to: [nil: "tajima@whoocus.com"] }
次に、Webアプリからメールを飛ばしてみる。コントローラを作成してルータに登録する。
ここでは、単純にページにアクセスしたら固定のメールが飛ぶ仕組み。
■ mail_controller.ex
defmodule MyApp.MailController do use MyApp, :controller alias MyApp.Mailer def index(conn, _params) do MyApp.Email.hello_email("tajima@whoocus.com") |> Mailer.deliver_now render conn, "index.html" end end
■ router.ex
get "/mail", MailController, :index
このページにアクセスする都度にメールが飛ぶ。
ここでは、個人的な試作のためにGmailを使用しているので、SMTPサーバへのアクセスと送信はそこそこ遅い。
メールサーバを立てる方が実用的である。
Phoenix static file の追加
uploads フォルダを、作成してブラウザから参照する場合。
priv/static/files を作成した場合の記述方法。
endpoint.ex
plug Plug.Static, at: "/", from: :sample, gzip: false, only: ~w(css fonts images js uploads favicon.ico robots.txt) # 参照名を追記 plug Plug.Static, at: "/uploads", from: "/files" # 参照名と、物理パス名を記述する。
Elixirの Enum.map と Enum.reduce の使いどころ
Elixirの Enum.map と Enum.reduce の使いどころを簡単に頭へ入るように簡単な例を示してみる。
■ Enum.map
iex(1)> list = [1,2,3,4,5] [1,2,3,4,5] iex(2)> Enum.map(list, fn(x)-> IO.puts x end) 1 2 3 4 5 [:ok, :ok, :ok, :ok, :ok]
次に簡略化して記述してみる。
iex(3)> Enum.map(list, &(IO.puts &1)) 1 2 3 4 5 [:ok, :ok, :ok, :ok, :ok]
同様の出力結果である。
list を頭に持ってきてみる。
iex(4)> list |> Enum.map(&(IO.puts &1)) 1 2 3 4 5 [:ok, :ok, :ok, :ok, :ok]
同様の出力結果である。
Phoenix でsession を使用する
■ PageController01 セッション設定
def index(conn, _params) do conn = put_session(conn, :msg01, "Hello session 01!!") conn = put_session(conn, :msg02, "Hello session 02!!") render conn, "index.html" end
■ PageController02 セッション取得
def index(conn, _params) do msg01 = get_session(conn, :msg01) msg02 = get_session(conn, :msg02) render(conn, "index.html", [msg01: msg01, msg02: msg02]) end
■ index.html.eex セッション格納データ表示
<div>MSG01: <%= @msg01 %></div> <div>MSG02: <%= @msg02 %></div>
Phoenix association belongs_to
■ member.ex
defmodule Sample.Portal.Member do use Ecto.Schema import Ecto.Changeset schema "members" do field :birthday, :date field :email, :string field :first_name, :string field :last_name, :string field :passwd, :string field :gender_cd, :integer # field :team_id, :id belongs_to :team, Sample.Portal.Team timestamps() end @doc false def changeset(member, attrs) do member |> cast(attrs, [:last_name, :first_name, :email, :passwd, :birthday, :team_id, :gender_cd]) |> validate_required([:last_name, :first_name, :email, :passwd, :birthday, :team_id ]) end end
■ repo.ex
def list_members do Repo.all(Member) |> Repo.preload(:team) end def get_member!(id), do: Repo.get!(Member, id) |> Repo.preload(:team)
■ index.html.eex
<%= for member <- @members do %> <td><%= member.team.team_name %></td> <% end %>
■ show.html.eex
<%= @member.team.team_name %>