OSDN Git Service

Regular updates
[twpd/master.git] / phoenix-ecto@1.2.md
1 ---
2 title: "Phoenix: Ecto models"
3 category: Elixir
4 deprecated: true
5 layout: 2017/sheet
6 tags: [Archived]
7 archived: This is for Phoenix 1.2 and below. [Phoenix 1.3 has a new API.](./phoenix-ecto@1.3).
8 ---
9
10 ### About
11
12 This is for Phoenix 1.2 and below. [Phoenix 1.3 has a new API.](./phoenix-ecto@1.3).
13
14 ### Generating
15
16 ```
17 $ mix phoenix.gen.html Profile profiles email:string age:integer
18 $ mix phoenix.gen.html User users email:string hashed_password:string
19 ```
20
21 ### Schema
22
23 ```elixir
24 defmodule User do
25   use Ecto.Schema
26
27   schema "users" do
28     field :name
29     field :age, :integer
30     # :id :binary :integer :float :boolean :string :binary
31     # {:array, inner_type} :decimal :map
32
33     field :password, virtual: true
34   end
35 end
36 ```
37
38 ### Changesets
39
40 ```elixir
41 def changeset(user, params \\ :empty) do
42   %User{}
43   |> Ecto.Changeset.change   # basic casting to changeset
44
45   user
46   |> cast(params, ~w(name email), ~w(age)) # params to Changeset
47
48   |> validate_format(:email, ~r/@/)
49
50   |> validate_inclusion(:age, 18..100)
51   |> validate_exclusion(:role, ~w(admin superadmin))
52   |> validate_subset(:pets, ~w(cat dog parrot whale))
53
54   |> validate_length(:body, min: 1)
55   |> validate_length(:body, min: 1, max: 160)
56   |> validate_length(:partners, is: 2)
57
58   |> validate_number(:pi, greater_than: 3)
59   |> validate_number(:pi, less_than: 4)
60   |> validate_number(:pi, equal_to: 42)
61
62   |> validate_change(:title, fn _, _ -> [])
63   |> validate_confirmation(:password, message: "does not match")
64
65   |> unique_constraint(:email)
66   |> foreign_key_constraint(:post_id)
67   |> assoc_constraint(:post)      # ensure post_id exists
68   |> no_assoc_constraint(:post)   # negative (useful for deletions)
69 end
70 ```
71
72 ```elixir
73 changeset.valid?
74 changeset.errors     #=> [title: "empty"]
75
76 changeset.changes    #=> %{}
77 changeset.params[:title]
78
79 changeset.required   #=> [:title]
80 changeset.optional   #=> [:body]
81 ```
82
83 ### Updating
84
85 ```elixir
86 changeset #(or model)
87 |> change(title: "New title")
88 |> change(%{ title: "New title" })
89 |> put_change(:title, "New title")
90 |> force_change(:title, "New title")
91 |> update_change(:title, &(&1 <> "..."))
92
93 |> delete_change(:title)
94 |> merge(other_changeset)
95
96 |> add_error(:title, "empty")
97 ```
98
99 ### Getting
100
101 ```elixir
102 get_change(changeset, :title)    #=> "hi" (if changed)
103 get_field(changeset, :title)     #=> "hi" (even if unchanged)
104
105 fetch_change(changeset, :title)  #=> {:ok, "hi"} | :error
106 fetch_field(changeset, :title)   #=> {:changes | :model, "value"} | :error
107 ```
108
109 ## Ecto
110
111 ### Get one
112
113 ```elixir
114 Repo.get(User, id)
115 Repo.get_by(User, email: "john@hello.com")  #=> %User{} | nil
116
117 # also get! get_by!
118 ```
119
120 ### Create/update
121
122 ```elixir
123 changeset |> Repo.update
124 changeset |> Repo.insert
125 changeset |> Repo.insert_or_update
126 ```
127
128 ```
129 User
130 |> Ecto.Changeset.change(%{name: "hi"})
131 |> Repo.insert
132 ```
133
134 ## Many
135
136 ### Queries
137
138 ```elixir
139 from p in Post,
140   where: p.title == "Hello",
141   where: [state: "Sweden"],
142
143   limit: 1,
144   offset: 10,
145
146   order_by: c.name,
147   order_by: [c.name, c.title],
148   order_by: [asc: c.name, desc: c.title],
149
150   preload: [:comments],
151   preload: [comments: {c, likes: l}],
152
153   join: c in assoc(c, :comments),
154   join: p in Post, on: c.post_id == p.id,
155   group_by: p,
156
157   select: p,
158   select: {p.title, p.description},
159   select: [p.title, p.description],
160 ```
161
162 ### Get many
163
164 ```elixir
165 Repo.all(User)
166 ```
167
168 ### Update many
169
170 ```elixir
171 Repo.update_all(Post, set: [title: "Title"])
172 Repo.update_all(Post, inc: [views: 1])
173 ```
174
175 ### Chaining `_all` with queries
176
177 ```elixir
178 from(p in Post, where: p.id < 10)
179 |> Repo.update_all(...)
180
181 from(p in Post, where: p.id < 10)
182 |> Repo.all()
183 ```