Create Foreign Key Relationship Between Ecto Tables: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
This document walks you through the creation of a has_many and belongs_to table relationship through the creation of two tables and these are '''Item''' and '''Group'''. | |||
The goal is to create two tables in Phoenix using the HTML generator. | |||
* Item(s) | |||
* Group(s) | |||
You will create a relationship between these two tables so that: | |||
* A Group can have many Items | |||
* Each Item can belong to 1 Group | |||
Steps | '''Steps''' | ||
In Phoenix | In Phoenix, generate the two tables and related UI code using these commands: | ||
<source> | <source> | ||
mix phx.gen.html | mix phx.gen.html Items Item items name:string | ||
mix phx.gen.html Groups Group groups name:string | mix phx.gen.html Groups Group groups name:string | ||
</source> | </source> | ||
The command line | Keep your eye on the command prompt. | ||
The command line will prompt you to add the '''resources /''' route for each table. Do what it says. | |||
After updating the routes, run the migrate command. | |||
<source> mix ecto.migrate </source> | |||
''' | '''Item Migration | ||
''' | ''' | ||
For | For items, you will create a migration file and add this field: group_id:references:groups. This is explained below. | ||
To create a migration file you CD into your app directory and run the migration creation | To create a migration file, you CD into your app directory and run the migration creation command below. Replace "name-of-migration" with "items_update" or similar. | ||
<source> | <source> | ||
Line 39: | Line 41: | ||
</source> | </source> | ||
In app/priv/repo/migrations is where the migration file is created. Update it to look like the following: | In app/priv/repo/migrations is where the migration file is created. Go to that directory and open the file with your text editor. Update it to look like the following: | ||
<source> | <source> | ||
def change do | def change do | ||
alter table(: | alter table(:items) do | ||
add :group_id, references(:groups) | add :group_id, references(:groups) # create association | ||
end | end | ||
end | end | ||
Line 50: | Line 52: | ||
'''Change Group Schema''' | '''Change Group Schema''' | ||
Update Group schema to look like the code below. | |||
<source> | <source> | ||
Line 57: | Line 59: | ||
import Ecto.Changeset | import Ecto.Changeset | ||
alias App. | alias App.Items.Item # Alias! | ||
schema "groups" do | schema "groups" do | ||
field :name, :string | field :name, :string | ||
has_many : | has_many :items, Item # Has many | ||
timestamps() | timestamps() | ||
end | end | ||
Line 75: | Line 77: | ||
</source> | </source> | ||
'''Change | '''Change Item Schema''' | ||
<source> | <source> | ||
defmodule App. | defmodule App.Items.Item do | ||
use Ecto.Schema | use Ecto.Schema | ||
import Ecto.Changeset | import Ecto.Changeset | ||
alias App.Groups.Group # Alias | alias App.Groups.Group # Alias | ||
schema " | schema "items" do | ||
field :name, :string | field :name, :string | ||
belongs_to :group, Group # Belongs to | belongs_to :group, Group # Belongs to | ||
Line 90: | Line 92: | ||
@doc false | @doc false | ||
def changeset( | def changeset(item, attrs) do | ||
item | |||
|> cast(attrs, [:name, :group_id]) # group_id | |> cast(attrs, [:name, :group_id]) # group_id | ||
|> validate_required([:name]) | |> validate_required([:name]) | ||
Line 98: | Line 100: | ||
</source> | </source> | ||
You will need to incorporate “preload” so that you can submit data. Go to app/lib/app/items.ex file and update it like this: | |||
<source> | <source> | ||
def | def list_items do | ||
Repo.all( | Repo.all(Item) | ||
|> Repo.preload([:group]) | |> Repo.preload([:group]) # Preload | ||
end | end | ||
</source> | </source> | ||
and this | Go to app/lib/app/groups.ex file and update it like this: | ||
<source> | <source> | ||
def list_groups do | def list_groups do | ||
Repo.all(Group) | Repo.all(Group) | ||
|> Repo.preload([: | |> Repo.preload([:items]) | ||
end | end | ||
</source> | </source> | ||
If you create Groups and Items and query them, the result looks like this: | |||
<source> | <source> | ||
Line 124: | Line 127: | ||
id: 3, | id: 3, | ||
name: "FUNK", | name: "FUNK", | ||
items: [], | |||
inserted_at: ~N[2023-09-27 18:13:15], | inserted_at: ~N[2023-09-27 18:13:15], | ||
updated_at: ~N[2023-09-27 18:13:15] | updated_at: ~N[2023-09-27 18:13:15] | ||
Line 130: | Line 133: | ||
</source> | </source> | ||
When I query | When I query Items they now look like this: | ||
<source> | <source> | ||
%App. | %App.Items.Item{ | ||
__meta__: #Ecto.Schema.Metadata<:loaded, " | __meta__: #Ecto.Schema.Metadata<:loaded, "items">, | ||
id: 1, | id: 1, | ||
name: "Bloop", | name: "Bloop", | ||
Line 144: | Line 147: | ||
</source> | </source> | ||
I now need to know how to write code that assigns a | I now need to know how to write code that assigns a Item to a Group. | ||
==Create | ==Create Table Entries == | ||
<source> | <source> | ||
App.Groups.create_group(%{name: " | App.Groups.create_group(%{name: "Group of items"}) | ||
App.Items.create_item(%{name: "an item"}) | |||
</source> | </source> | ||
== Assign an Existing Item to a Group == | |||
== | |||
<source> | <source> | ||
group = App.Groups.get_group!(1) | group = App.Groups.get_group!(1) | ||
item = App.Items.get_item!(1) | |||
App.Items.update_item(item, %{group_id: group.id}) | |||
</source> | </source> | ||
Run this code to view the result. You will see the group with a field name | Run this code to view the result. You will see the group with a field name items that is assigned a List. The List contains a Item struct. | ||
<source> | <source> | ||
Line 172: | Line 170: | ||
</source> | </source> | ||
== Assign | ==Submit Item and Assign to a Group Association== | ||
This code will create a new item "on the fly" and assign it to the Group that has an ID of 1. | |||
<source> | <source> | ||
group = App.Groups.get_group!(1) | group = App.Groups.get_group!(1) | ||
thing = Ecto.build_assoc(group, :items, name: "DUMB") | |||
App. | alias App.{Repo} | ||
Repo.insert(thing) | |||
</source> | </source> |
Revision as of 10:44, 10 October 2023
This document walks you through the creation of a has_many and belongs_to table relationship through the creation of two tables and these are Item and Group.
The goal is to create two tables in Phoenix using the HTML generator.
- Item(s)
- Group(s)
You will create a relationship between these two tables so that:
- A Group can have many Items
- Each Item can belong to 1 Group
Steps
In Phoenix, generate the two tables and related UI code using these commands:
mix phx.gen.html Items Item items name:string mix phx.gen.html Groups Group groups name:string
Keep your eye on the command prompt. The command line will prompt you to add the resources / route for each table. Do what it says.
After updating the routes, run the migrate command.
mix ecto.migrate
Item Migration
For items, you will create a migration file and add this field: group_id:references:groups. This is explained below.
To create a migration file, you CD into your app directory and run the migration creation command below. Replace "name-of-migration" with "items_update" or similar.
mix ecto.gen.migration name-of-migration
In app/priv/repo/migrations is where the migration file is created. Go to that directory and open the file with your text editor. Update it to look like the following:
def change do alter table(:items) do add :group_id, references(:groups) # create association end end
Change Group Schema Update Group schema to look like the code below.
defmodule App.Groups.Group do use Ecto.Schema import Ecto.Changeset alias App.Items.Item # Alias! schema "groups" do field :name, :string has_many :items, Item # Has many timestamps() end @doc false def changeset(group, attrs) do group |> cast(attrs, [:name]) |> validate_required([:name]) end end
Change Item Schema
defmodule App.Items.Item do use Ecto.Schema import Ecto.Changeset alias App.Groups.Group # Alias schema "items" do field :name, :string belongs_to :group, Group # Belongs to timestamps() end @doc false def changeset(item, attrs) do item |> cast(attrs, [:name, :group_id]) # group_id |> validate_required([:name]) end end
You will need to incorporate “preload” so that you can submit data. Go to app/lib/app/items.ex file and update it like this:
def list_items do Repo.all(Item) |> Repo.preload([:group]) # Preload end
Go to app/lib/app/groups.ex file and update it like this:
def list_groups do Repo.all(Group) |> Repo.preload([:items]) end
If you create Groups and Items and query them, the result looks like this:
%App.Groups.Group{ __meta__: #Ecto.Schema.Metadata<:loaded, "groups">, id: 3, name: "FUNK", items: [], inserted_at: ~N[2023-09-27 18:13:15], updated_at: ~N[2023-09-27 18:13:15] }
When I query Items they now look like this:
%App.Items.Item{ __meta__: #Ecto.Schema.Metadata<:loaded, "items">, id: 1, name: "Bloop", group_id: nil, group: nil, inserted_at: ~N[2023-09-27 14:04:15], updated_at: ~N[2023-09-27 18:22:23] }
I now need to know how to write code that assigns a Item to a Group.
Create Table Entries
App.Groups.create_group(%{name: "Group of items"}) App.Items.create_item(%{name: "an item"})
Assign an Existing Item to a Group
group = App.Groups.get_group!(1) item = App.Items.get_item!(1) App.Items.update_item(item, %{group_id: group.id})
Run this code to view the result. You will see the group with a field name items that is assigned a List. The List contains a Item struct.
App.Groups.list_groups
Submit Item and Assign to a Group Association
This code will create a new item "on the fly" and assign it to the Group that has an ID of 1.
group = App.Groups.get_group!(1) thing = Ecto.build_assoc(group, :items, name: "DUMB") alias App.{Repo} Repo.insert(thing)