Goal
Micropostモデルを作成する。
Dev-Environment
OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Phoenix Framework: v0.13.1
PostgreSQL: postgres (PostgreSQL) 9.4.4
Wait a minute
ようやっとユーザ以外のモデルを作成します。
今回の内容は特に難しいことはないと思います。
今回の内容は特に難しいことはないと思います。
気楽にやっていきましょう~
Index
Create Micropost model
|> Migration of Micropost model
|> User has many Micropost, Also Micropost belongs to User
|> Delete together
|> Validation
|> Extra
|> Migration of Micropost model
|> User has many Micropost, Also Micropost belongs to User
|> Delete together
|> Validation
|> Extra
Migration of Micropost model
マイクロポストのモデルを作成するため、マイグレーションします。
データモデルは以下のようになります。
モデル名: Micropost
テーブル名: microposts
作成するカラム: content(string)、user_id(integer)
自動生成されるカラム: id(integer)、inserted_at(timestamp)、updated_at(timestamp)
モデル名: Micropost
テーブル名: microposts
作成するカラム: content(string)、user_id(integer)
自動生成されるカラム: id(integer)、inserted_at(timestamp)、updated_at(timestamp)
インデックスに指定するカラムは以下の二つです。
インデックス: user_id(integer)、inserted_at(timestamp)
インデックス: user_id(integer)、inserted_at(timestamp)
インデックスは、こんな感じのソースコードになりますね。
create index(:microposts, [:user_id, :inserted_at], concurrently: true)
まずは、コマンドで自動生成をします。
>mix phoenix.gen.model Micropost microposts content:string user_id:integer
* creating priv/repo/migrations/timestamp_create_micropost.exs
* creating web/models/micropost.ex
* creating test/models/micropost_test.exs
ファイル: priv/repo/migrations/timestamp_create_micropost.exs
マイグレーションファイルを以下のように編集する。
マイグレーションファイルを以下のように編集する。
defmodule SampleApp.Repo.Migrations.CreateMicropost do
use Ecto.Migration
@disable_ddl_transaction true
def change do
create table(:microposts) do
add :content, :string
add :user_id, :integer
timestamps
end
create index(:microposts, [:user_id, :inserted_at], concurrently: true)
end
end
マイグレーションを実行。
>mix ecto.migrate
14:20:27.485 [info] == Running SampleApp.Repo.Migrations.CreateMicropost.change/0 forward
14:20:27.485 [info] create table microposts
14:20:27.504 [info] create index microposts_user_id_inserted_at_index
14:20:27.523 [info] == Migrated in 0.3s
DBの方を確認しましょう。問題なしですね。
Description:
@disable_ddl_transaction属性は、
トランザクションの外部で実行するように強制できる属性です。
@disable_ddl_transaction属性は、
トランザクションの外部で実行するように強制できる属性です。
記述していないと以下のようなエラーがDBのログに書き出されます。
2015-07-29 14:06:19 JST ERROR: CREATE INDEX CONCURRENTLYはトランザクションブロックの内側では実行できません
2015-07-29 14:06:19 JST ステートメント: CREATE INDEX CONCURRENTLY "microposts_user_id_inserted_at_index" ON "microposts" ("user_id", "inserted_at")
User has many Micropost, Also Micropost belongs to User
ユーザは複数のマイクロポストを持ち、マイクロポストはユーザに属する設定を実施する。
作成したMicropostモデルと、既に作成しているUserモデルを紐づけます。
作成したMicropostモデルと、既に作成しているUserモデルを紐づけます。
既に何度かご紹介している機能です。
- Ecto.Schema.has_many/3
- Ecto.Schema.belongs_to/3
この二つを利用します。
表示する部分を作成していないので、設定だけになりますが・・・
次の記事にて、行いますのでしばしお待ちを・・・
表示する部分を作成していないので、設定だけになりますが・・・
次の記事にて、行いますのでしばしお待ちを・・・
ファイル: web/models/user.ex
schema "users" do
field :name, :string
field :email, :string
field :password_digest, :string
field :password, :string, virtual: true
has_many :microposts, SampleApp.Micropost
timestamps
end
ファイル: web/models/micropost.ex
schema "microposts" do
field :content, :string
belongs_to :user, SampleApp.User, foreign_key: :user_id
timestamps
end
Delete together
ユーザが削除されたら、そのユーザのマイクロポストも削除します。
そうでなくては、ユーザの登録が消えているのに、
マイクロポストだけが残ってしまいますね。
そうでなくては、ユーザの登録が消えているのに、
マイクロポストだけが残ってしまいますね。
UserControllerのDeleteアクションに処理を追加するだけです。
ファイル: web/controllers/user_controller.ex
deleteアクションを以下のように修正します。
deleteアクションを以下のように修正します。
def delete(conn, %{"id" => id}) do
user = Repo.get(SampleApp.User, id)
from(m in SampleApp.Micropost, where: m.user_id == ^user.id) |> Repo.delete_all
Repo.delete(user)
conn
|> put_flash(:info, "User deleted successfully.")
|> redirect(to: static_pages_path(conn, :home))
end
Validation
マイクロポストに対して、Validationを追加します。
ファイル: web/models/micropost.ex
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> validate_length(:content, min: 1)
|> validate_length(:content, max: 140)
end
Extra
多対1の簡単な動作テストをしてみます。
iex上で実行します。
iex上で実行します。
Caution:
user_idは、存在しているユーザのidを指定して下さい。
user_idは、存在しているユーザのidを指定して下さい。
Exsample:
マイクロポストのデータを作成。
マイクロポストのデータを作成。
iex(1)> changeset = SampleApp.Micropost.changeset(%SampleApp.Micropost{}, %{content: "hogehoge", user_id: 7})
...
iex(2)> SampleApp.Repo.insert(changeset)
...
Exsample:
紐づいたデータが取得できるか確認。
紐づいたデータが取得できるか確認。
iex(3)> SampleApp.User |> SampleApp.Repo.get(7) |> SampleApp.Repo.preload [:microposts]
...
%SampleApp.User{__meta__: %Ecto.Schema.Metadata{source: {nil, "users"},
state: :loaded}, email: "nuke@nuke.com", id: 7,
inserted_at: #Ecto.DateTime<2015-07-23T10:27:19Z>,
microposts: [%SampleApp.Micropost{__meta__: %Ecto.Schema.Metadata{source: {nil,
"microposts"}, state: :loaded}, content: "hugehuge", id: 3,
inserted_at: #Ecto.DateTime<2015-07-29T06:30:46Z>,
updated_at: #Ecto.DateTime<2015-07-29T06:30:46Z>,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: 7}], name: "nuke", password: nil,
password_digest: "S3RtK2pSN1hnSExtSzhUeVpCWjZWUT09LS1wdVZ2MmlpSEtYMjhlZHhXRkp1cUd3PT0=--37D3577AE91D1F5DFB99AD354463046F82733790",
updated_at: #Ecto.DateTime<2015-07-23T10:27:19Z>}
ついでに、画面上からユーザを削除してみて下さい。
紐づいたマイクロポストも削除されていることが確認できると思います。
紐づいたマイクロポストも削除されていることが確認できると思います。
Speaking to oneself
migrationのup/downとchangeについて初めて知りましたよ。
そういう意味があったんですね~(無知)
参考: tanihiro.log -【Rails】migrationのchangeとup/downって何が違うの?
そういう意味があったんですね~(無知)
参考: tanihiro.log -【Rails】migrationのchangeとup/downって何が違うの?
今回、Ecto.rollbackを初めて使いました。
@disable_ddl_transaction属性を忘れていまして・・・一度、戻したんですよ。
@disable_ddl_transaction属性を忘れていまして・・・一度、戻したんですよ。
便利です。rollback機能。