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