links: [[Phoenix MOC]] --- # Create a table in Phoenix app from command line Phoenix provides generators for a quick bootstrap of schema, views, controllers and even context. The command is a *mix* task and starts with *phx.gen* followed by necessary arguments Let's say I want to generate a basic CRUD for users with email, password `mix phx.gen.html Accounts User users user_id:uuid email:string:unique password_hash:string time_joined: string` This command will create necessary files for CRUD operations in controllers, views, a context named Account, a migration file Now, let's say I dont' want to name *id* as default primary key, instead I would like to have *user_id*. We need to tell our phoenix about that - open the migration file created by phoenix (it's under priv folder) - Inside the `create_table` arguments add *primary_key: false*. This tells phoenix not to create primary key with id - Now add *primary_key: true* to *user_id* (add :user_id, :uuid, primary_key: true, null: false) The output will look like this: ```elixir def change do create table(:users, primary_key: false) do add :user_id, :uuid, primary_key: true, null: false add :email, :string, null: false add :password_hash, :string add :time_joined, :utc_datetime timestamps() end ``` Now run the migration with the following command `mix ecto.migrate` which will apply this to database We still need to modify few things in other files, since phoenix assumes *id* as the default primary key. we need to instruct phoenix to consider *user_id* as primary key Open `user.ex` file created in *accounts* context folder. - Inside the users schema, comment out *user_id* field. - On top of users schema, add the following code ```elixir @primary_key {:user_id, Ecto.UUID, autogenerate: true} @derive {Phoenix.Param, key: :user_id} ``` We are instructing to use *user_id* as primary key, which is a type of *UUID* and also to take care of auto generating it. Now for the *@derive* directive part. This tells to use different key name for the routes, the reason to add derive is it manages data structure to an ID in the routes. The final result would be something like this ```elixir @primary_key {:user_id, Ecto.UUID, autogenerate: true} @derive {Phoenix.Param, key: :user_id} schema "users" do field :email, :string field :password_hash, :string, redact: true field :time_joined, :utc_datetime # field :user_id, Ecto.UUID timestamps() end ``` In modern versions of phoenix, you can also achieve same thing as follows. This can be used for composite keys ```elixir @primary_key false @derive {Phoenix.Param, key: :user_id} schema "users" do field :email, :string field :password_hash, :string, redact: true field :time_joined, :utc_datetime field :user_id, Ecto.UUID, primary_key: true timestamps() end ``` --- tags: #database, #migrations source: - [https://stackoverflow.com/questions/57083826/phoenix-problem-when-get-model-with-two-custom-primary-key](StackOverFlow) - [https://hexdocs.pm/phoenix/1.3.0-rc.2/custom_primary_key.html](Old Docs) - [https://medium.com/@brucepomeroy/specifying-primary-key-values-with-ecto-57405b7ecbc5](specifying primary key values with ecto)