Phoenix v1.7.10／LiveView v0.20.1でScrivenerを使おうとした① -Scrivener導入

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はPhoenix1.7にScrivenerを導入してみた手順をまとめます。
なお、今回の記事は下記の記事を参考にPhoenix1.7でやってみたログです。

 https://qiita.com/koyo-miyamura/items/663230bf4bc61e80a711

# 目次
1.Scrivener導入(本記事)
2.[ページネーションコンポーネントの作成](https://qiita.com/Alicesky2127/items/a16fc554ef0779c4cfc6)

# 目的 
Phoenix1.7にScrivenerを導入してページネーションをつけたい。

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2
Phoenix v1.7.10
LiveView v0.20.1

# 今回やりたいこと
Phoenix1.7.10／LiveView v0.20.1のプロジェクトにScrivenerを導入したい。

# Scrivenerとは？
ページネーションを作るライブラリ。
後述しますが、今回はEcto.Repoを使用してページネーションを作りたいので、下記`scrivener_ecto`を使用します。

https://github.com/drewolson/scrivener_ecto

# 準備
## Ectoスキーマの作成
`mix phx.gen.live`でEctoスキーマを作ってもらいます。

```shell:bash
mix phx.new nov11
cd nov11
mix phx.gen.live Users User users name:string age:integer
```

```diff_elixir:/lib/nov11_web/router.ex
 scope "/", Nov11Web do
     pipe_through :browser

+    live "/users", UserLive.Index, :index
+    live "/users/new", UserLive.Index, :new
+    live "/users/:id/edit", UserLive.Index, :edit

+    live "/users/:id", UserLive.Show, :show
+    live "/users/:id/show/edit", UserLive.Show, :edit

     get "/", PageController, :home
 end
```

```shell:bash
mix ecto.migrate
```


## seedデータの作成
```diff_elixir:priv/repo/seeds.exs
+ alias Nov11.Users

+ 1..20
+ |> Enum.each(fn x -> Users.create_user(%{name: "user#{x}", age: "#{x + 10}"}) end)
```
```shell:bash
mix run priv/repo/seeds.exs
```

user1からuser20までのデータが投入されました。
```diff_elixir:iex
[
  %Nov11.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "hogehoge",
    age: 10,
    inserted_at: ~U[2023-11-11 14:34:43Z],
    updated_at: ~U[2023-11-11 14:34:43Z]
  },
  %Nov11.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 5,
    name: "piyopiyo",
    age: 30,
    inserted_at: ~U[2023-12-06 00:15:35Z],
    updated_at: ~U[2023-12-06 00:15:35Z]
  },  
  %Nov11.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 4,
    name: "hogefuga",
    age: 20,
    inserted_at: ~U[2023-12-06 00:15:28Z],
    updated_at: ~U[2023-12-11 14:12:04Z]
  },
  %Nov11.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 6,
    name: "user1",
    age: 11,
    inserted_at: ~U[2023-12-17 11:00:36Z],
    updated_at: ~U[2023-12-17 11:00:36Z]
  },
  %Nov11.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 7,
    name: "user2",
    age: 12,
    inserted_at: ~U[2023-12-17 11:00:36Z],
    updated_at: ~U[2023-12-17 11:00:36Z]
  }
  ...
]
```

画面上はこんな感じです。
なお、先頭のデータ3件はCRUD機能の確認のために画面上で手入力したものなのでスルーしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/956fbbd9-0f8d-eed6-9084-ed644bf1b8b1.png)



# Scrivenerの導入
```diff_elixir:mix.exs
defp deps do
    [
      #中略
-     {:plug_cowboy, "~> 2.5"}
+     {:plug_cowboy, "~> 2.5"},
+     {:scrivener_ecto, "~> 2.0"}
    ]
  end
```

```shell:bash
mix deps.get
```

# Scrivenerの初期設定
repo.exに下記を追加
```diff_elixir:lib/nov11/repo.ex
 defmodule Nov11.Repo do
   use Ecto.Repo,
     otp_app: :nov11,
     adapter: Ecto.Adapters.Postgres

+  use Scrivener, page_size: 5
 end
```

Userの一覧を取得する関数を変更
```diff_elixir:lib/nov11/users.ex
   def list_users do
-    Repo.all(User)
+    Repo.paginate(User)
   end
```

# Scrivenerの検証
```shell:bash
iex -S mix
```

```diff_elixir:iex
iex(1)> users = Nov11.Users.list_users
%Scrivener.Page{
  page_number: 1,
  page_size: 5,
  total_entries: 23,
  total_pages: 5,
  entries: [
    %Nov11.Users.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 1,
      name: "hogehoge",
      age: 10,
      inserted_at: ~U[2023-11-11 14:34:43Z],
      updated_at: ~U[2023-11-11 14:34:43Z]
    },
    %Nov11.Users.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 5,
      name: "piyopiyo",
      age: 30,
      inserted_at: ~U[2023-12-06 00:15:35Z],
      updated_at: ~U[2023-12-06 00:15:35Z]
    },
    %Nov11.Users.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 4,
      name: "hogefuga",
      age: 20,
      inserted_at: ~U[2023-12-06 00:15:28Z],
      updated_at: ~U[2023-12-11 14:12:04Z]
    },
    %Nov11.Users.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 6,
      name: "user1",
      age: 11,
      inserted_at: ~U[2023-12-17 11:00:36Z],
      updated_at: ~U[2023-12-17 11:00:36Z]
    },
    %Nov11.Users.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      id: 7,
      name: "user2",
      age: 12,
      inserted_at: ~U[2023-12-17 11:00:36Z],
      updated_at: ~U[2023-12-17 11:00:36Z]
    }
  ]
}
```

`%Scrivener.Page{}`でデータ全体が囲まれました。

画面上ではこうなります↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/54ff211e-cb9a-d379-0ccd-bb0d27f9a483.png)


# Scrivenerで遊んでみた
## page_sizeを変えてみる
第二引数`page_size`の値は1ページあたりに表示するデータの件数を決定します。
`page_size`が与えられていない場合は、`repo.ex`に記載したデフォルト値(今回なら`page_size: 5`)が適用されます。

### 例: `page_size: 2`のとき
```diff_elixir:lib/nov11/users.ex
   def list_users do
-    Repo.all(User)
+    Repo.paginate(User, page_size: 2)
   end
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/40f0cbf2-be45-a8f0-236a-a76b12f7189d.png)


Scrivenerの導入はできました(^▽^)/

# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian




[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！