Phoenix Elixir – Deploy Phoenix Apps on Heroku

Heroku merupakan salah satu tempat publish apps yang free, daftarkan akun anda pada website heroku di https://signup.heroku.com/ dan service heroku dapat digunakan. Heroku juga support dengan bahasa pemrograman elixir dan phoenix framework tentunya.. Bagaimana langkah men-deploy aplikasi phoenix pada Heroku? Phoenix sendiri sudah menjelaskan tahapan ini pada website resmi phoenix framework https://hexdocs.pm/phoenix/heroku.html, tapi saya akan menjelaskan beberapa detail yang saya alami dalam men-deploy project phoenix ke heroku.

Proses pertama yang harus dilakukan adalah mendaftarkan email anda pada web heroku dan siapkan project phoenix yang akan di-deploy.

Initialisasi project dengan git, hal ini juga akan membantu proses deploy ke depan. Untuk diketahui project yang di deploy dapat dihubungkan dengan server heroku melalui git, artinya setiap perintah commit yang dijalankan pada project akan mengupdate (setelah dilakukan push ke server heroku) file project pada server. Untuk melakukan initialisasi project dengan git, arahkan directory terminal ke directory project kemudian jalankan perintah berikut pada terminal:

$ git init
$ git add .
$ git commit -m "Initial commit"

Install heroku toolbelt, download di https://toolbelt.heroku.com/. Heroku toolbelt digunakan untuk menjalankan perintah2 heroku melalui terminal. Setelah menginstall heroku toolbelt, masukkan perintah berikut pada terminal:

$ heroku -v

Jika heroku toolbelt telah terinstal terminal akan menampilkan pesan berikut (versi bisa berbeda):

heroku-cli/6.14.30-304197d (darwin-x64) node-v8.5.0

 

MEMBUAT APLIKASI HEROKU

Kita akan membuat aplikasi baru pada heroku dengan heroke toolbelt. Pertama-tama pastikan terminal sudah berada pada direktori project yang akan di -deploy, kemudian login melalui heroku toolbelt, masukkan perintah

$ heroku login

Buat aplikasi baru dengan perintah berikut:

$ heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git"
Creating stark-savannah-17693... done, stack is cedar-14 Buildpack set. Next release on mysterious-meadow-6277 will use https://github.com/HashNuke/heroku-buildpack-elixir.git. 
https://stark-savannah-17693.herokuapp.com/ | https://git.heroku.com/stark-savannah-17693.git

Perintah di atas akan membuat aplikasi pada heroku. Nama aplikasi heroku yang dibuat digenerate secara acak.

Kita harus mendefinisikan environment apa saja yang dibutuhkan pada aplikasi heroku yang dibuat, misal kita ingin server tersebut memiliki environment PHP 5.7, Elixir x.x, Erlang x.x. Heroku akan membaca environment ini dari sebuah file buildpack yang diletakkan pada root project. Kita juga dapat mendefinisikan buildpack dengan menambahkan perintah “–buildpack” pada proses create aplikasi baru. Pada perintah di atas aplikasi yang dibuat akan memiliki buildpack dari tautan yang didefinisikan.

Jika ditelusur ke dalam tautan buildpack diatas, environment yang diminta adalah berikut:

erlang_version=19.3
elixir_version=1.4.2
always_rebuild=false
runtime_path=/app

Anda dapat memodifikasi buildpack di atas jika diperlukan.

Selain buildpack tersebut, phoenix masih membutuhkan beberapa environment agar dapat dijalankan pada heroku. Masukkan perintah berikut

$ heroku buildpacks:add https://github.com/gjaldon/heroku-buildpack-phoenix-static.git 
Buildpack added. Next release on stark-savannah-17693 will use: 
1. https://github.com/HashNuke/heroku-buildpack-elixir.git 
2. https://github.com/gjaldon/heroku-buildpack-phoenix-static.git 
Run `git push heroku master` to create a new release using these buildpacks.

Perintah di atas menambahkan buildpack tambahan seperti library dan komponen yang diperlukan oleh phoenix framework.

Setiap kita masukkan perintah heroku, secara otomatis perintah tersebut akan berpengaruh pada project yang didefinisikan sebelumnya. Namun dalam kondisi anda menutup terminal (yah pasti butuh istirahat kan?), kita dapat mengarahkan perintah terminal ke aplikasi yang dituju dengan perintah:

heroku git:remote -a [our-app-name]

KONFIGURASI APLIKASI

Aplikasi phoenix memilik konfigurasi pada file “config/prod.secret.exs” dimana secara default file tersebut masuk ke dalam daftar .gitignore (file tersebut tidak masuk pada proses commit melalui git). Hal ini menyebabkan file configurasi tidak ditemukan pada heroku. Kita akan memindahkan configurasi aplikasi dari “config/prod.secret.exs” ke “config/prod.exs”. Modifikasi code pada “config/prod.exs” seperti berikut:

config :myapp, Myapp.Endpoint,
http: [port: {:system, "PORT"}],
url: [scheme: "https", host: "your heroku app url", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
cache_static_manifest: "priv/static/manifest.json",
secret_key_base: Map.fetch!(System.get_env(), "SECRET_KEY_BASE")

Konfigurasi di atas mengarahkan url aplikasi ke url heroku. Kita juga mendefinisikan nilai “secret_key_base” dengan nilai dari (System.get_env(), “SECRET_KEY_BASE”).

Dari mana dan apa System.get_env() ??

System.get_env() adalah nilai yang tersimpan pada server. Penggunaan System.get_env() sering digunakan untuk nilai yang bersifat rahasia seperti token, password, API secret, dll. Hal ini karena dengan System.get_env() tidak perlu menuliskan informasi rahasia tersebut langsung ke dalam code aplikasi, tapi di generate ke dalam variabel server (selanjutnya akan dicontohkan cara menambahkan suatu variabel keserver)

Tambahkan juga code berikut untuk untuk configurasi database:

config :myapp, Myapp.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true

Konfigurasi di atas mengatur koneksi database yang digunakan pada heroku.  Karena informasi database rahasia, akan dimasukkan juga dengan System.get_env(). Kita tidak lagi menggunakan file “config/prod.secret.exs” sehingga kita dapat menghapus baris berikut:

import_config "prod.secret.exs"

Karena heroku memiliki batas minimun 55 detik waktu timeout, kita perlu mengurangi timeout untuk websocket transport. Pada file “web/channels/user_socket.ex” (untuk phoenix versi 1.3 file ini terdapat pada “lib/myapp/channels/user_socket.ex”) modifikasi code menjadi seperti berikut:

defmodule Myapp.UserSocket do 
   use Phoenix.Socket 
   ... 

   ## Transports 
   transport :websocket, Phoenix.Transports.WebSocket, 
   timeout: 45_000 
   ... 
end

Untuk men-deploy aplikasi pada heroku, kita perlu membuat file “Procfile” pada root aplikasi. File ini selanjutnya dibaca oleh heroku server untuk menjalankan perintah terminal awal saat menjalankan aplikasi pada heroku. Buatlah sebuah file dengan nama “Procfile” pada root project dan masukkan perintah berikut (untuk phoenix 1.2 atau kebawah bisa dengan “mix phoenix.server”):

web: MIX_ENV=prod mix phx.server

Kita telah menyelesaikan konfigurasi aplikasi, selanjutnya menambahkan konfigurasi variabel pada server.

DATABASE_URL

Nilai “DATABASE_URL” secara otomatis sudah ditambahkan ke dalam konfigurasi server saat kita membuat database postgresql pada heroku. Untuk membuat database pada baru pada heroku, masukkan perintah berikut pada terminal:

heroku addons:create heroku-postgresql:hobby-dev

Database yang dibuat juga dapat dilihat melalui web dashboard heroku.

 

POOL_SIZE

Konfigurasi nilai POOL_SIZE dengan memasukkan menjalankan perintah berikut:

$ heroku config:set POOL_SIZE=18

 

SECRET_KEY_BASE

Pertama-tama kita harus dapatkan nilai secret key dari aplikasi dengan menjalankan perintah berikut (untuk phoenix 1.2 dengan mix phoenix.gen.secret) :

mix phx.gen.secret xvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53

Nilai yang di dapat barulah di arahkan ke dalam server heroku dengan perintah berikut:

heroku config:set SECRET_KEY_BASE="xvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53"

Selesai konfigurasi variabel, selanjutnya adalah men-deploy project ke dalam heroku server. Sebelum men-deploy project, commit seluruh perubahan yang telah dilakukan pada langkah di atas. Kemudian deploy project dengan perintah berikut:

$ git push heroku master

Proses deploy akan memakan waktu, juga tergantung koneksi internet yang dimiliki. Jika proses deploy berjalan tanpa pesan error, artinya project berhasil di deploy hingga dan dapat diakses di server heroku.

BEBERAPA KONDISI DAN PROBLEM

Terdapat beberapa permasalahan umum yang terjadi pada proses deploy project phoenix ke server heroku. Berikut permasalahannya dan pemecahannya:

 

ERLANG TIDAK DAPAT DIINSTAL

Terkadang Heroku gagal dalam melakukan installasi erlang bisa jadi karena versi Erlang yang tidak support atau kesalahan penulisan version. Jika versi Erlang memang tidak di support, kita harus mengubah versi Erlang yang di support oleh Heroku. Untuk kesalahan penulisan sering terjadi karena kita menuliskan versi Erlang seperti berikut:

erlang_version=19
elixir_version=1.3.4

harusnya ditulis seperti berikut:

erlang_version=19.0
elixir_version=1.3.4

 

MIGRASI DATABASE

Mengelola database Heroku tidak semudah mengelola database pada komputer lokal karena Heroku tidak menyediakan fitur untuk mengelola database (untuk versi gratisan) seperti menambah tabel, manambah kolom, insert data, dll. Satu-satunya cara mendefinisikan tabel2 tersebut ke dalam database adalah menjalankan perintah database pada aplikasi. Yah… phoenix punya fitur migrate untuk mengelola schema database. Kita cukup menjalankan perintah migrate database dengan perintah berikut:

migrate database: heroku run "POOL_SIZE=2 mix ecto.migrate"

 

Selesai.. itulah langkah men-deploy project phoenix ke Heroku.. Semoga berhasil, happy coding…

Advertisements

Phoenix Elixir – Using System.get_env()

Jika pada suatu kasus anda tidak ingin menyimpan sebuah informasi rahasia langsung pada kode anda (ex: API key, client secret, dll), maka anda dapat menyimpan variabel tersebut pada environment variabel. Variabel ini akan disimpan pada environment anda dan dapat digunakan oleh aplikasi dengan cara seperti berikut :

System.get_env("MY_SECRET")

Bagaimana cara mendefinisikan variabel “MY_SECRET” pada environment anda?

Buat sebuah file “.env” pada root aplikasi, dan masukkan code berikut untuk mengatur nilai variabel:

export MY_SECRET="i_love_you"
export HER_SECRET="she_dont_love_me"

dari contoh di atas kita mendefinisikan variabel “MY_SECRET” dan “HER_SECRET” pada environment kita. Kemudian jalankan perintah “source .env” pada terminal kemudian aktifkan server anda. Anda sudah dapat memanggil variabel tersebut pada aplikasi anda.

Happy coding.. 😀

Xamarin iOS – Custom UIAlertAction Style With SetValueForKey

UIAlertAction merupakan komponen list pada UIAlertController dimana ditampilkan dalam bentuk text. Style pada  UIAlertAction dapat dimodifikasi dengan cara berikut :


     UIAlertAction temp = UIAlertAction.Create(head, UIAlertActionStyle.Default, alert => { /* your function here */ }); 

     temp.SetValueForKey(UIColor.Black, (NSString)"titleTextColor");
     temp.SetValueForKey(UIImage.FromBundle("your image path"), (NSString)"image"); 
     listAlertController.AddAction(temp);

Pada contoh di atas kita membuat sebuah UIAlertAction yang di definisikan pada variabel “temp”. Modifikasi style pada variabel temp dilakukan dengan “SetValueForKey”, dimana kita akan menyisipkan property suatu nilai berdasarkan nama property nya (pastikan property yang di set memiliki nama yang benar, kesalahan nama akan menyebabkan error). Untuk kasus di atas kita melakukan custom property “titleTextColor” untuk warna dari label dan “image” untuk menambahkan icon pada label.

 

Sekian, happy coding…

Phoenix Elixir – Using Preload to Call Relation Data

Phoenix Elixir – Using Preload to call Relation Data

Phoenix Framework menyediakan sebuah fitur untuk memudahkan developer menampilkan field-field pada tabel yang berelasi dengan suatu tabel tanpa harus melakukan query yang berulang. Sebagai contoh terdapat tabel “mothers” dan tabel “children” dimana setiap data pada tabel “children” akan memiliki field “mother_id” yang merupakan foreign_key dari tabel “mothers”. Berikut adalah class model mothers :

defmodule App.Mother do
  use App.Web, :model

  schema "mother" do
    field :name, :string
  end
end

Dan berikut class dari tabel “Children” :

defmodule App.Children do
  use App.Web, :model

  schema "children" do
    field :label, :string
    field :mother_id, :integer
  end
end

Saya asumsikan kita ingin menampilkan semua data dari tabel “Children”, berikut query yang kita gunakan :

 query = from u in Children,
                select: u

 datas = Repo.all(query)

Variabel “datas” akan menyimpan semau data dari tabel “children” dengan field “label” dan “mother_id”. Pengguna tidak akan tahu apa arti dari “mother_id” karena data yang ditampilkan berupa “id” bukan nama. Untuk mengatasi masalah ini, phoenix menyediakan fitur untuk memanggil field “name” dari tabel mother. Berikut langkah-langkahnya :

Pada class “Children” lakukan modifikasi pada schema sebagai berikut:

  schema "children" do
    field :label, :string
    belongs_to :mother, App.Mother
  end

Code di atas akan mendefinisikan relation pada tabel children yang mengarah pada tabel mother. Relation bernama “:mother” akan membuat Phoenix secara otomatis membaca field yang be-relasi (foreign key) adalah field “mother_id” (field dengan tambahan “_id” dari nama relasi). Untuk itu pastikan nama field anda sesuai dengan nama relation ditambah “_id”.

Berikut cara memanggil seluruh data children beserta data dari tabel relasinya :

    query = from u in Children,
                select: u

    datas = Repo.all(query)
          |> Repo.preload(:mother)

Bagaimana jika kita memiliki sebuah database yang telah memasuki tahap production sehingga tidak memungkinkan mengikuti nama field sesuai kaedah dari Phoenix? Jangan khawatir, Phoenix telah menyediakan sebuah mekanisme yang memungkinkan anda bebas melakukan pengaturan dengan relation anda. Sebagai contoh tabel “Children” memiliki field relation dengan nama “id_mother”, maka buatlah schema anda seperti berikut :

  schema "children" do
    field :label, :string
    field :id_mother, :integer
    belongs_to :mother, App.Mother, define_field: false, foreign_key: :id_mother
  end

Anda juga dapat mendefinisikan lebih dari satu field relasi pada suatu schema. Sebagai contoh:

  schema "children" do
    field :label, :string
    field :id_mother, :integer
    belongs_to :mother, App.Mother, define_field: false, foreign_key: :id_mother
    belongs_to :another_relation, App.AnotherRelation
  end

Kedua relasi tersebut dapat dipanggil dengan cara berikut :

   query = from u in Children,
                select: u

    datas = Repo.all(query)
          |> Repo.preload([:mother, :another_relation])

Itulah semua yang perlu anda lakukan untuk mengatur relasi tabel anda… Selesai, selamat mencoba..

Happy coding..

Phoenix Elixir – Make Authenticate Page (Register, Login, Logout)

Phoenix Elixir – Make Authenticate Page (Register, Login, Logout)

Postingan kali ini akan memaparkan bagaimana membuat fitur autentikasi pada Phoenix Framework yang terdiri dari fitur register, login dan logout. Sebelum kita lanjutkan ke tahapan membuat proses register, saya asumsikan anda sudah memahami cara membuat fitur CRUD pada Phoenix Framework (bisa dilihat di https://sabitlabscode.wordpress.com/2017/01/04/phoenix-elixir-make-crud-with-postgresql/ bagi anda yang belum paham). Proses register dimulai dengan men-generate CRUD tabel user dengan field tabel sebagai berikut : username , name , password dan email. Semua field yang dibuat memiliki tipe string kecuali field id dan timestamps() yang dibentuk otomatis oleh Phoenix. Setelah melakukan generate CRUD pada tabel user, pastikan seluruh fungsi CRUD berjalan dengan baik. Untuk mempersingkat maka proses “register” yang dibuat adalah proses action “new” dan “create” pada UserController (anda bisa membuat fungsi register tersendiri untuk memperindah managemen code anda), ke depannya kita akan arahkan tautan register ke action tersebut.

Guna meningkatkan security pada proses autentikasi, kita harus melakukan beberapa modifikasi berikut pada proses register yang dibuat sebelumnya:

  • enkripsi pada field password. Setiap user yang melakukan proses register, field password yang diisi oleh user harus di enkripsi kemudian disimpan ke dalam database.
  • User harus mengisi password sebanyak 2 kali (password dan password confirmation) untuk memastikan password yang dimasukkan benar.

Untuk menambahkan password confirmation, kita harus menambahkan sebuah field pada model “User” dan menandakan field tersebut menjadi sebuah field virtual yang sebenarnya tidak ada pada tabel. Berikut schema pada model User setelah ditambahkan field password confirmation:

schema "users" do
    field :username, :string
    field :name, :string
    field :password, :string
    field :email, :string
    field :password_confirmation, :string, virtual: true

    timestamps()
  end

Tambahkan juga field tersebut pada form.html.eex. Ketika pengguna menginput data user ke dalam form, maka aplikasi harus memastikan bahwa antara field password dan password_confirmation harus sama. Masukkan validasi berikut pada model User untuk melakukan pengecekan tersebut :

 @required_fields ~w(username name email password password_confirmation)
  @optional_fields ~w()
  @doc """
  Builds a changeset based on the `struct` and `params`.
  """

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @required_fields)
    |> validate_required([:username, :name, :password, :password_confirmation, :email])
    |> validate_format(:email, ~r/@/, message: "Please fix your email format")
    |> validate_confirmation(:password)
  end

Validasi “validate_confirmation” akan mengecek kesamaan field parameter dengan field yang bernama parameter+”_confirmation” dalam hal ini “password” dan “password_confirmation.

Ingat, ketika melakukan proses penyimpanan maka aplikasi akan melakukan enkripsi field password. Buatlah sebuah fungsi untuk melakukan enkripsi pada model User :

  def generate_password_and_store_user(changeset) do
    put_change(changeset, :password, hashpwsalt(changeset.params["password"]))
      |> Repo.insert
  end

Fungsi di atas dapat dipanggil dengan parameter sebuah “changeset”. Nilai dari changeset tersebut akan memodifikasi changeset dengan parameter “password” dimana nilainya diganti dengan nilai hasil enkripsi. Setelah merubah nilai pada parameter “password” dilakukan proses insert data ke database.

Import Comeonin agar dapat menggunakan fungsi “hashpwsalt” pada proses enkripsi :

 import Comeonin.Bcrypt, only: [hashpwsalt: 1]

Pada UserController action create, masukkan code berikut :

 def create(conn, %{"user" => user_params}) do
    changeset = User.changeset(%User{}, user_params)
    if changeset.valid? do
      new_user = User.generate_password_and_store_user(changeset)

      conn
        |> put_flash(:info, "Successfully registered and logged in")
        |> redirect(to: user_path(conn, :index))
    else
      render conn, "new.html", changeset: changeset
    end
  end

Yang terjadi pada code di atas adalah :

  • mendefinisikan variabel “changeset” yang di dapat dari post form “new” dan dibundle ke dalam User changeset
  • jika variabel changeset sudah memenuhi validasi pada model User, maka akan memanggil fungsi “generate_password_and_store_user pada model User. Fungsi ini akan memodifikasi field password untuk kemudian disimpan ke dalam database.

Proses register telah dapat anda jalankan..

LOGIN dan LOGOUT

Proses login dan logout akan kita letakkan pada sebuah controller terpisah. Buatlah sebuah controller dengan nama AuthController. Di dalam controller ini akan terdapat fungsi “login”, “authenticate” dan “logout”. Berikut code pada AuthController :

defmodule MyApp.AuthController do
  use FotoKerja.Web, :controller

  def login(conn, _params) do
    render(conn, "login.html")
  end

  def authenticate(conn, %{"user" => user_params}) do
    case MyApp.Auth.login(user_params, FotoKerja.Repo) do
      {:ok, user} ->
        conn
        |> put_session(:current_user, user.id)
        |> put_flash(:info, "Logged in")
        |> redirect(to: "/")
      :error ->
        conn
        |> put_flash(:info, "Wrong email or password")
        |> render("login.html")
    end
  end

  def logout(conn, _) do
    conn
      |> delete_session(:current_user)
      |> put_flash(:info, "Logged out")
      |> redirect(to: "/")
  end

end

Action “login” hanya akan menampilkan sebuah form “login.html”, form ini berisi field username dan password untuk proses login. Action “authenticate” akan bertindak sebagai “post” pada action login dimana disini akan mengecek inputan login user dari fungsi Auth.login yang akan kita buat nanti. Sedangkan fungsi logout akan menghapus session “:current_user” yang artinya menghapus session user yang sedang login.

Untuk kebutuhan view pada proses login, buatlah sebuah file “web/views/auth_view.ex” dengan code berikut :

defmodule FotoKerja.AuthView do
  use FotoKerja.Web, :view
end

Dan file “web/templates/auth/login.html.eex” yang berisi text input username dan password. Untuk username gunakan text_input dan password gunakan password_input.

Tambahkan file “web/models/auth.ex”, file ini akan melakukan proses login. Masukkan code berikut :

defmodule MyApp.Auth do
   alias MyApp.User

  def login(params, repo) do
    user = repo.get_by(User, username: String.downcase(params["username"]))
    case authenticate(user, params["password"]) do
      true -> {:ok, user}
      _    -> :error
    end
  end

  defp authenticate(user, password) do
    case user do
      nil -> false
      _   -> Comeonin.Bcrypt.checkpw(password, user.password)
    end
  end

  def current_user(conn) do
    id = Plug.Conn.get_session(conn, :current_user)
    if id, do: FotoKerja.Repo.get(User, id)
  end

  def logged_in?(conn), do: !!current_user(conn)
end

Code di atas terdiri dari beberapa fungsi, berikut penjelasan masing-masing fungsi :

  • authenticate : fungsi ini akan mengecek apakah password seorang user sudah sama dengan password yang diinput oleh user yang mencoba login. Tentunya pengecekan password akan menggunakan fungsi dari Comeonin untuk matching dengan nilai yang di enkripsi.
  • login : fungsi authenticate akan dipanggil pada fungsi ini, fungsi login pertama-tama akan memanggil data user yang meiliki “username” yang sama seperti nilai username yang diinput pada proses login. Jika data username tersebut ada pada database, barulah fungsi “authenticate” dipanggil untuk mengecek password.
  • current_user : akan mengembalikan data user yang sedang login
  • logged_in : mengecek apakah orang yang mengakses aplikasi dalam kondisi login atau tidak

Kembali pada “UserController” pada action authenticate yang memanggil Auth.login untuk proses autentikasi. Seperti dapat anda lihat bahwa fungsi Auth.login akan mengecek kebenaran “username” kemudian memanggil “authenticate” untuk mengecek kebenaran “password”.

Informasi tentang user yang telah melakukan proses login akan disimpan ke dalam session “:curent_user”. Dapat dilhat pada “UserController” ketika proses ketika proses login berhasil dilakukan, akan menjalankan perintah berikut :

        |> put_session(:current_user, user.id)

Perintah di atas akan menyimpan data session “:current_user” ke dalam data dengan data “user.id”. Dan ketika melihat AuthController action “logout”, kita menemukan code untuk menghapus nilai session :current_user seperti berikut :

      |> delete_session(:current_user)

Selanjutnya kita akan membuat sebuah tautan dengan kondisi sebagai berikut :

  • Jika user belum login, akan menampilkan tautan untuk login dan register
  • Jika user telah login, akan menampilkan email user dan tautan untuk logout.
  • Kita akan meletakkan tautan tersebut pada bagian atas/header aplikasi

Masukkan code berikut pada “web/templates/layout/app.html.eex” :

           <%= if logged_in?(@conn) do %>
              <li><%= current_user(@conn).email %></li>
              <li><%= link "Logout", to: auth_path(@conn, :logout), method: :delete %></li>
            <% else %>
              <li><%= link "Login",    to: "/login" %></li>
              <li><%= link "Register", to: user_path(@conn, :new) %></li>
            <% end %>

Kita memanggil fungsi logged_in dan current_user yang ada pada model Auth. Agar template di atas dapat menggunakan kedua fungsi tersebut, kita harus melakukan import pada file “web/web.ex” tepatnya di dalam fungsi “view” seperti berikut :

      import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]

Setelah modifikasi di atas, silahkan jalankan aplikasi.. anda dapat melakukan proses login seperti berikut :

jan-11-2017-02-13-24

Thanks to :

http://nithinbekal.com/posts/phoenix-authentication/

http://meatherly.github.io/2015/05/11/phoenixauthentication/

Happy coding…

Xamarin iOS – Dynamic UITabBarController

Xamarin iOS – Dynamic UITabBarController

Untuk kebutuhan yang lebih spesifik, kita dapat membuat kumpulan UIViewController pada UITabBarController secara dinamis. Tahapannya adalah :

  • Tambahkan sebuah UIViewController (xib file) yang akan digunakan secara dinamis pada UITabBarController. Misal dalam contoh ini saya akan membuat sebuah file UIViewController dengan nama “DynamicController”
  • Pada UITabBarController, tambahkan sebuah button atau UITBarButtonItem yang digunakan untuk memberi perintah menambahkan DynamicController ke dalam UITabBar
  • Masukkan code berikut untuk menambah bar dengan DynamicController
 List<UIViewController> temp_list = new List<UIViewController>(this.ViewControllers);
 UIViewController new_tab = new DynamicController();
 new_tab.TabBarItem.Title = "Item #" + (temp_list.Count + 1).ToString();
 temp_list.Add(new_tab);

 this.ViewControllers = temp_list.ToArray();

Yang terjadi pada code di atas adalah :

  • Mendefinisikan variabel temp_list dalam bentuk list dan kita masukkan semua array pada this.ViewControllers (array UIViewController yang sudah ada pada BarItem
  • Mendefinisikan variabel “new_tab” yang berisi UIViewController yang akan ditambahkan
  • Konfigurasi judul TabBar untuk UIViewController “new_tab”
  • Menambahakan list “temp_list” dengan UIViewController baru
  • Atur ulang nilai this.ViewControllers

Source saya ada di : https://github.com/sabithuraira/xamarin_ios_playground/commit/3c5ea649474c69192f264461667082f267e6878b

Happy coding…

Phoenix Elixir – About Ecto

Phoenix Elixir – About Ecto

Ecto adalah sebuah source yang digunakan agar aplikasi dapat terhubung ke database pada bahasa pemrograman Elixir, dan Phoenix Framework juga menggunakan Ecto untuk komunikasi antara database dan aplikasi. Jika anda mengikuti panduan create aplikasi Phoenix baru pada tautan berikut http://www.phoenixframework.org/docs/up-and-running, maka Ecto secara otomatis terinstall pada aplikasi anda.

Secara default Ecto pada Phoenix akan menggunakan database postgreSQL, jika ingin menggunakan database lain harus dilakukan beberapa konfigurasi terlebih dahulu. Pendefenisian Ecto pada aplikasi terdapat pada file “web/mix.exs” pada code :

 def application do
    [mod: {FirstApp, []},
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex]]
 end

 defp deps do
    [{:phoenix, "~> 1.2.1"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"}]
  end

Pada konfigurasi di atas dapat dilihat telah didefinisikan phoenix_ecto dan postgrex sebagai database. Sedangkan untuk menghubungkan aplikasi dengan suatu database postgreSQL lakukan konfigurasi pada file “config/dev.exs” tepatnya pada code berikut :

# Configure your database
config :first_app, FirstApp.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  database: "first_app_dev",
  hostname: "localhost",
  pool_size: 10

Code diatas mendefinisikan identitas database yang akan digunakan mulai dari username dan password, nama database dan attribute lainnya.

MIGRATION

Ecto memungkinkan anda membuat tabel/schema melalui fitur Migration (Ecto.Migration). Sebagai contoh kita akan membuat sebuah tabel “users” pada database. Lakukan pendefinisian file migration pada “priv/repo/migrations” misalnya file “create_user.exs”. Masukkan code berikut :

defmodule FirstApp.Repo.Migrations.CreateUser do
  use Ecto.Migration
  def change do
    create table(:users) do
      add :name, :string
      add :email, :string
      add :birth, :date
      add :age, :integer
      timestamps()
    end
  end
end

File Ecto.Migration di atas akan membuat table users dengan field name, email, birth dan age dengan tipe data yang telah tertera pada masing-masing field. Tabel users juga akan menambahkan field inserted_at dan updated_at yang sudah dimasukkan melalui fungsi “timestamps()”. Untuk menjalankan perintah membuat schema database pada file migration, jalankan perintah berikut pada terminal.

$ mix ecto.migrate

Setelah menjalankan perintah tersebut tabel users akan terbentuk pada database anda dengan tambahan “id” sebagai primary key (id ditambah otomatis oleh Ecto).

MODEL

Komponen MODEL pada MVC Phoenix juga menggunakan Ecto. Model sendiri adalah representasi data pada database termasuk kumpulan field, tipe data, validasi, dll. Berikut adalah contoh class model yang didapat dari tabel User :

defmodule FirstApp.User do
  use FirstApp.Web, :model

  schema "users" do
    field :name, :string
    field :email, :string
    field :birth, Ecto.Date
    field :age, :integer
    timestamps()
  end

  @doc """
  Builds a changeset based on the `struct` and `params`.
  """
  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :email, :birth, :age])
    |> validate_required([:name, :email, :birth, :age])
    |> validate_length(:name, min: 3)
    |> validate_length(:email, min: 5)
    |> validate_format(:email, ~r/@/, message: "Please fix your email format")
  end
end

Pada contoh di atas kita dapat melihat schema user yang terdiri dari beberapa field beserta jenis data masing-masing field. Model juga memiliki changeset yang digunakan untuk meletakkan validasi, mengatur pesan error, mendefinisikan model pada form, mendefinisikan data untuk proses update/insert, dll.

MENAMPILKAN DATA

Ecto menggunakan “Repo” untuk komunikasi data antara aplikasi dan database. Anda dapat menggunakan Ecto query atau Ecto model untuk mengambil data pada database yang kemudian dapat digunakan pada aplikasi. Untuk menampilkan seluruh data pada tabel “users” ggunakan Repo dan Model dengan code seperti berikut :

    Repo.all(User) 

User merupakan class model User.

Menampilkan suatu data berdasarkan id/primary key tertentu gunakan code berikut :

    Repo.get(User, id)

atau gunakan code berikut untuk menjalankan peirntah yang sama tetapi menampilkan pesan error saat data tidak ditemukan :

    Repo.get!(User, id)

Untuk menampilkan data yang memiliki nilai attribute tertentu :

 Repo.get_by(User, name: “John")

atau gunakan code berikut untuk menjalankan peirntah yang sama tetapi menampilkan pesan error saat data tidak ditemukan :

 Repo.get_by!(User, name: “John”)

Selain memadukan Repo dan Model, kita dapat memadukan Repo dan Query guna mendapatkan data dengan query yang lebih kompleks. Berikut contoh codenya :

 query = from u in User,
                where: u.age == 26,
                select: u

 users = Repo.all(query)

Code di atas akan menampilkan data yang memiliki field age = 26.

MODIFIKASI DATA

Ecto Repo juga menyediakan fitur untuk melakukan proses modifikasi data (update, insert, delete). Proses insert data dapat dilakukan dengan code berikut :

      case Repo.insert %User{name: “Jhon”,age: “26”,birth: “1989-01-01”,email: “jhon@email.com”} do
        {:ok, struct}       -> # Insert something for success process
        {:error, changeset} -> # Insert something for wrong process
      end

Anda dapat melakukan insert data dengan mengambil langsung variabel dari changeset pada model :

    changeset = User.changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, _user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: user_path(conn, :index))
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end

Untuk proses update data gunakan Repo.update :

    user = Repo.get!(User, id)
    changeset = User.changeset(user, user_params)

    case Repo.update(changeset) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User updated successfully.")
        |> redirect(to: user_path(conn, :show, user))
      {:error, changeset} ->
        render(conn, "edit.html", user: user, changeset: changeset)
    end

Dan untuk delete gunakan Repo.delete :

    user = Repo.get!(User, id)
    Repo.delete!(user)

Selesai, itulah sedikit pembahasan tentang Ecto.. Happy coding..

%d bloggers like this: