スポンサーリンク

2017年3月29日

alchemist report 007

Header

About

ElmでJsonのリストデータをデコードする簡易サンプル。

Body

自作した関数
idDecoder =
  (Decode.field "id" Decode.int)

nameDecoder =
  (Decode.field "name" Decode.string)

emailDecoder =
  (Decode.field "email" Decode.string)

userDecoder =
  Decode.map3 User.Schema idDecoder nameDecoder emailDecoder

usersDecoder =
  Decode.list userDecoder

usersDataDecoder =
  (Decode.field "data" usersDecoder)
デコードしたデータを格納するモデル(?)
type alias Schema =
  { id : Int
  , name : String
  , email : String
  }
elm replの実行ログ

> import Json.Decode exposing (..)

> jsonList = "{\"data\":[{\"name\":\"hoge\",\"id\":1,\"email\":\"hoge@test.com\"},{\"name\":\"foo\",\"id\":2,\"email\":\"bar@test.com\"}]}" "{\"data\":[{\"name\":\"hoge\",\"id\":1,\"email\":\"hoge@test.com\"},{\"name\":\"foo\",\"id\":2,\"email\":\"bar@test.com\"}]}"     : String

> decodeString usersDataDecoder jsonList Ok ([{ id = 1, name = "hoge", email = "hoge@test.com" },{ id = 2, name = "foo", email = "bar@test.com" }])     : Result.Result String (List Model.User.Schema)

footer

実行ログの表示がバグってるので見づらいと思われる。(このブログのマークダウンで変換すると表示がバグる)
下記のリンク先にあるREADMEを見た方がわかりやすいかも
darui00kara/front_elm_back_phoenix

2017年3月25日

Environment Elixir(v1.4)&Phoenix(v1.3)&Elm(v0.18)

Header

Env

$ erl +V
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 8.3

$ elixir -v
Erlang/OTP 19 [erts-8.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.4.2

$ node -v
v7.7.3

$ postgres --version
postgres (PostgreSQL) 9.6.1

$ elm -v
0.18.0
Elm not installed? Let’s install!

Example:

$ npm install -g elm

Body

Example

$ mix phx.new elm_elixir_phx
... 
Fetch and install dependencies? [Yn] y
* running mix deps.get
* running mix deps.compile
* running cd assets && npm install && node node_modules/brunch/bin/brunch build

We are all set! Run your Phoenix application:

    $ cd elm_elixir_phx
    $ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phx.server

Before moving on, configure your database in config/dev.exs and run:

    $ mix ecto.create

$ cd elm_elixir_phx
$ mix ecto.create
$ mix phx.gen.json Accounts User users name:string email:string
* creating lib/elm_elixir_phx/web/controllers/user_controller.ex
* creating lib/elm_elixir_phx/web/views/user_view.ex
* creating test/web/controllers/user_controller_test.exs
* creating lib/elm_elixir_phx/web/views/changeset_view.ex
* creating lib/elm_elixir_phx/web/controllers/fallback_controller.ex
* creating lib/elm_elixir_phx/accounts/user.ex
* creating priv/repo/migrations/20170325054157_create_accounts_user.exs
* creating lib/elm_elixir_phx/accounts/accounts.ex
* creating test/accounts_test.exs

Add the resource to your api scope in lib/elm_elixir_phx/web/router.ex:

    resources "/users", UserController, except: [:new, :edit]

Remember to update your repository by running migrations:

    $ mix ecto.migrate

File: lib/elm_elixir_phx/web/router.ex

defmodule ElmElixirPhx.Web.Router do
  use ElmElixirPhx.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", ElmElixirPhx.Web do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  scope "/api", ElmElixirPhx.Web do
    pipe_through :api

    resources "/users", UserController, except: [:new, :edit]
  end
end
$ mix ecto.migrate

14:46:40.278 [info]  == Running ElmElixirPhx.Repo.Migrations.CreateElmElixirPhx.Accounts.User.change/0 forward

14:46:40.279 [info]  create table accounts_users

14:46:40.283 [info]  == Migrated in 0.0s
$ cd assets 
$ npm install --save-dev elm-brunch

File: assets/package.json

{
  "repository": {},
  "license": "MIT",
  "scripts": {
    "deploy": "brunch build --production",
    "watch": "brunch watch --stdin"
  },
  "dependencies": {
    "phoenix": "file:../deps/phoenix",
    "phoenix_html": "file:../deps/phoenix_html"
  },
  "devDependencies": {
    "babel-brunch": "6.0.6",
    "brunch": "2.10.7",
    "clean-css-brunch": "2.10.0",
    "css-brunch": "2.10.0",
    "elm-brunch": "^0.8.0",
    "uglify-js-brunch": "2.1.1"
  }
}
$ mkdir lib/elm
$ cd lib/elm
$ elm make
Some new packages are needed. Here is the upgrade plan.

  Install:
    elm-lang/core 5.1.1
    elm-lang/html 2.0.0
    elm-lang/virtual-dom 2.0.4

Do you approve of this plan? [Y/n] y
Starting downloads...

  ● elm-lang/html 2.0.0
  ● elm-lang/virtual-dom 2.0.4
  ●
elm-lang/core 5.1.1
Packages configured successfully!
Success! Compiled 37 modules.
exports.config = {
  ...

  // Phoenix paths configuration
  paths: {
    // Dependencies and current project directories to watch
    watched: ["static", "css", "js", "vendor", "../lib/elm/Endpoint.elm"],
    // Where to compile files to
    public: "../priv/static"
  },

  // Configure your plugins
  plugins: {
    elmBrunch: {
      elmFolder: "../lib/elm",
      mainModules: ["Endpoint.elm"],
      outputFolder: "../../assets/vendor"
    },
    babel: {
      // Do not use ES6 compiler in vendor code
      ignore: [/vendor/]
    }
  },

  ...
};

File: lib/elm/Endpoint.elm

module Endpoint exposing (..)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode

type alias User =
  { name  : String
  , email : String
  , id    : Int
  }

type alias UserData =
  { data : User }

type Msg =
  LoadUserData ( Result Http.Error User )
  | Name String
  | Email String
  | Signup

-- main

main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

init : (User, Cmd Msg)
init =
  ( { name = "none", email = "none", id = 0 }
  , sendRequest
  )

update : Msg -> User -> ( User, Cmd Msg )
update msg user =
  case msg of
    LoadUserData ( Ok newUser ) ->
      ( newUser, Cmd.none )
    LoadUserData ( Err _ ) ->
      ( user, Cmd.none )
    Signup ->
      ( user, Cmd.none )
    Name name ->
      ( { user | name = name }, Cmd.none )
    Email email ->
      ( { user | email = email }, Cmd.none )

view : User -> Html Msg
view user =
  div []
    [ h2 [] [ text user.name ]
    , h2 [] [ text user.email ]
    , div []
        [ h2 [] [ text "Signup Form" ]
        , label [ for "name-field" ] [ text "Name:" ]
        , input [ id "name-field", type_ "text", placeholder "Name", onInput Name ] []
        , label [ for "email-field" ] [ text "Email:" ]
        , input [ id "email-field", type_ "text", placeholder "Email", onInput Email ] []
        , button [ onClick Signup ] [ text "signup" ]
        ]
    ]

subscriptions : User -> Sub Msg
subscriptions user =
  Sub.none

-- decoder

idDecoder =
  ( Decode.field "id" Decode.int )

nameDecoder =
  ( Decode.field "name" Decode.string )

emailDecoder =
  ( Decode.field "email" Decode.string )

userDecoder =
  Decode.map3 User nameDecoder emailDecoder idDecoder

userDataDecoder =
  ( Decode.field "data" userDecoder )

-- request

getUserUrl : String
getUserUrl =
  "http://localhost:4000/api/users/1"

getUser : Http.Request User
getUser =
  Http.get getUserUrl userDataDecoder

sendRequest : Cmd Msg
sendRequest =
  Http.send LoadUserData getUser

File: lib/elm_elixir_phx/web/templates/page/index.html.eex

<div class="jumbotron">
  <h2><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h2>
  <p class="lead">A productive web framework that<br />does not compromise speed and maintainability.</p>
</div>

<div id="elm-main"></div>

<div class="row marketing">
  <div class="col-lg-6">
    <h4>Resources</h4>
    <ul>
      <li>
        <a href="http://phoenixframework.org/docs/overview">Guides</a>
      </li>
      <li>
        <a href="https://hexdocs.pm/phoenix">Docs</a>
      </li>
      <li>
        <a href="https://github.com/phoenixframework/phoenix">Source</a>
      </li>
    </ul>
  </div>

  <div class="col-lg-6">
    <h4>Help</h4>
    <ul>
      <li>
        <a href="http://groups.google.com/group/phoenix-talk">Mailing list</a>
      </li>
      <li>
        <a href="http://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on freenode IRC</a>
      </li>
      <li>
        <a href="https://twitter.com/elixirphoenix">@elixirphoenix</a>
      </li>
    </ul>
  </div>
</div>
$ elm package install elm-lang/http
To install elm-lang/http I would like to add the following
dependency to elm-package.json:

    "elm-lang/http": "1.0.0 <= v < 2.0.0"

May I add that to elm-package.json for you? [Y/n] y

Some new packages are needed. Here is the upgrade plan.

  Install:
    elm-lang/http 1.0.0

Do you approve of this plan? [Y/n] y
Starting downloads...

  ● elm-lang/http 1.0.0

Packages configured successfully!
iex(1)> alias ElmElixirPhx.Accounts, as: Accounts
ElmElixirPhx.Accounts
iex(2)> Accounts.create_user(%{name: "hoge", email: "hoge@test.com"})
[debug] QUERY OK db=4.0ms
INSERT INTO "accounts_users" ("email","name","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" ["hoge@test.com", "hoge", {{2017, 3, 25}, {7, 15, 55, 261888}}, {{2017, 3, 25}, {7, 15, 55, 268724}}]
{:ok,
 %ElmElixirPhx.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "accounts_users">,
  email: "hoge@test.com", id: 1, inserted_at: ~N[2017-03-25 07:15:55.261888],
  name: "hoge", updated_at: ~N[2017-03-25 07:15:55.268724]}}
iex(3)> Accounts.get_user!(1)
[debug] QUERY OK source="accounts_users" db=1.7ms
SELECT a0."id", a0."email", a0."name", a0."inserted_at", a0."updated_at" FROM "accounts_users" AS a0 WHERE (a0."id" = $1) [1]
%ElmElixirPhx.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "accounts_users">,
 email: "hoge@test.com", id: 1, inserted_at: ~N[2017-03-25 07:15:55.261888],
 name: "hoge", updated_at: ~N[2017-03-25 07:15:55.268724]}
$ mix phx.server

Footer

none

人気の投稿