13
3

More than 3 years have passed since last update.

作って学ぶPhoenix、Railsのアレどうやんの?随時更新

Last updated at Posted at 2020-03-06

RailsチュートリアルをPhoenixで実装しました。 https://github.com/pojiro/sample_app

Phoenixではどうやるか?をまとめています。随時更新します。

※RailsはRailsチュートリアルでしかさわったことがありません。

bundle install

$ mix deps.get

railsコマンド

rails new

$ mix phx.new

rails console

$ iex -S mix

rails server

$ mix phx.server

rails db:create

$ mix ecto.create

rails db:migrate:reset & rails db:seed

$ mix ecto.reset # aliasなので、自身のプロジェクトのmix.exsのdeps aliasesを見ること

rails generate migration

$ mix ecto.gen.migration

rails db:migrate

$ mix ecto.migrate

rails db:rollback

$ mix ecto.rollback

rails test

$ mix test

rails destroy

ない。gitでdiscardする。

modelのメソッドはどこに書くの?

schemaをラップするコンテキストモジュールに関数を作成する。

RailsとPhoenixは思想が大きく異なる。
Railsでは、データと関数のペアのクラスでモデルを定義するが、
Phoenixでは、データと関数をモジュールを分けて定義する。
schemaとchangesetをデータ側にそのデータを操作する関数の集まりをコンテキストモジュールとして定義する。

これはruby(オブジェクト指向)とelixir(関数型)の思想の違いによる。Phoenixでオブジェクト指向をやるのはよくない。

validates

validatesの各キーはそれぞれ関数として用意される。

  • presence => validate_required
  • length => validate_length
  • format => validate_format
  • uniqueness => unique_constraint

Ecto.Changesetのドキュメント

provide & yield

Phoenixではtemplate内での変数参照はPlug.connストラクトのassignsを介して行う。
渡したいデータはassign(conn, key, value)すると、template内では@ keyで参照できる。

Plug.Connのドキュメント

flash

put_flash(conn, key, message)をつかう。
template側で取るときはget_flash(conn, key)

ファイルのアップロード

form_forでfile_inputを使う。[multipart: true]を忘れないようにする。

<%= form_for @changeset, Routes.micropost_path(@conn, :create), [multipart: true], fn f-> %>
  <div class="field">
    <%= textarea f, :content, placeholder: "Compose new micropost..." %>
    <%= error_tag f, :content %>
  </div>
  <span class="picture">
    <%= file_input f, :picture, class: "form-control" %>
    <%= error_tag f, :picture %>
  </span>
  <%= content_tag :input, nil, type: "submit", class: "btn btn-primary", value: "Post" %>
<% end %>

sessionメソッド

put_session(conn, key, value)
get_session(conn, key)
delete_session(conn, key)
  • expire期間をkey毎に設定できない。一律にはできる。
    (endpoint.exのPlug.sessionにmax_ageオプションを設定する)
  • デフォルトは改ざん防止のために署名される。
  • 暗号化も可能。(endpoint.exのPlug.sessionにencryption_saltオプションを設定する)

cookiesメソッド

put_resp_cookie(conn, key, value)
get_resp_cookie(conn, key)
delete_resp_cookie(conn, key)
  • 署名、暗号化はされないので、必要な場合はput_resp_cookieする前に行う。Phoenic.Tokenが便利
  • expire期間をkey毎に設定できる。

before_action

plugを作って、

# 例
def logged_in_user(conn, _opts) do
  if logged_in?(conn) do
    conn
  else
    conn
    |> SessionHelper.store_location()
    |> put_flash(:error, "Please log in.")
    |> redirect(to: Routes.session_path(conn, :new))
    |> halt()
  end
end

コントローラにつなぐ。

defmodule SampleAppWeb.UserController do
  use SampleAppWeb, :controller
  plug :logged_in_user when action in [:index, :show, :edit, :update, :delete]
  ...
end

request.referer

List.first(get_req_header(conn, "referer"))

assert_select

flokiを使ってassertすればやりたいことはできるはず。

conn = get(logged_in_conn, Routes.user_path(conn, :show, user))

parsed_html = Floki.parse_document!(html_response(conn, 200))
assert Floki.find(parsed_html, "h1") |> Floki.text() =~ user.name

テストの自動実行、guard

guardに相当するのがmix_test_watch

$ bundle exec guard # rails
$ mix test.watch # phoenix

テスト結果の通知、minitest-reporters

ex_unit_notifierを使う。

heroku

herokuに相当するのがgigalixir。
コマンドも同じようにつくられているようだ。

$ heroku logs
$ gigalixir logs

$ heroku run rails db:migrate
$ gigalixir run mix ecto.migrate
13
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3