Goal
マイクロポストの投稿と削除を実装する。
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
いや~、前回の記事では修正量が多くてすませんでした。
お付き合い頂いた方には感謝です。
お付き合い頂いた方には感謝です。
マイクロポストを画面から投稿/削除できるようにします。
やったね!iexから地味な作業をしなくても、操作できるようになるよ!!
やったね!iexから地味な作業をしなくても、操作できるようになるよ!!
後、フィードは今回実装しません。
詳しくは独り言を読んで下さい。
詳しくは独り言を読んで下さい。
Index
Operation of Micropost
|> Creating a Micropost controller
|> Sign-in required
|> Micropost Posts
|> Delete of Micropost
|> Creating a Micropost controller
|> Sign-in required
|> Micropost Posts
|> Delete of Micropost
Creating a Micropost controller
マイクロポストを投稿/削除を実装するため、
Create、Deleteアクションが必要です。
そのためのコントローラを作成します。
Create、Deleteアクションが必要です。
そのためのコントローラを作成します。
ファイル: web/router.ex
ルーティングを追加。
ルーティングを追加。
resources "/post", MicropostController, only: [:create, :delete]
Description:
only:[action]で特定のアクションのみ選択している。
今回は、createとdeleteアクションを選択。
only:[action]で特定のアクションのみ選択している。
今回は、createとdeleteアクションを選択。
気になる人は、以下のコマンドで確認してみる。
mix phoenix.routes
ファイル: web/controllers/micropost_controller.ex
以下のように編集。
以下のように編集。
defmodule SampleApp.MicropostController do
use SampleApp.Web, :controller
plug SampleApp.Plugs.CheckAuthentication
plug :action
def create(conn, _params) do
end
def delete(conn, _params) do
end
end
Sign-in required
サインイン状態でないと操作をできないようにします。
UserControllerでやっているように、MicropostControllerにも
signed_in_user?/2 を実装すればいいのでしょうか?
UserControllerでやっているように、MicropostControllerにも
signed_in_user?/2 を実装すればいいのでしょうか?
それは機能の重複ですね。ナンセンスです。
なので、signed_in_user?/2 をCheckAuthenticationと同じようにモジュールプラグに変更します。
なので、signed_in_user?/2 をCheckAuthenticationと同じようにモジュールプラグに変更します。
ファイル: lib/plugs/signed_in_user.ex
以下のように実装。
以下のように実装。
defmodule SampleApp.Plugs.SignedInUser do
import Plug.Conn
import Phoenix.Controller, only: [put_flash: 3, redirect: 2]
import SampleApp.Router.Helpers, only: [session_path: 2]
def init(options) do
options
end
def call(conn, _) do
if conn.assigns[:current_user] do
conn
else
conn
|> put_flash(:info, "Please sign-in.")
|> redirect(to: session_path(conn, :new))
|> halt
end
end
end
Description:
移しただけですね。しかし、ちょっとだけ説明を書きます。
importで特定の使いたい関数だけ取り込んでいます。
移しただけですね。しかし、ちょっとだけ説明を書きます。
importで特定の使いたい関数だけ取り込んでいます。
ファイル: web/controllers/user_controller.ex
以下の二つを削除。
以下の二つを削除。
plug :signed_in_user? when action in [:index, :show, :edit, :update, :delete]
defp signed_in_user?(conn, _) do
...
end
以下を追加。
機能プラグの部分がモジュールプラグを指定するようになっただけですね。
機能プラグの部分がモジュールプラグを指定するようになっただけですね。
plug SampleApp.Plugs.SignedInUser when action in [:index, :show, :edit, :update, :delete]
ファイル: web/controllers/micropost_controller.ex
以下を追加。
以下を追加。
plug SampleApp.Plugs.SignedInUser
これで準備よし。
Micropost Posts
マイクロポストの投稿を実装します。
Createアクションの実装です。
Createアクションの実装です。
ファイル: web/models/micropost.ex
関数の追加。
関数の追加。
def new_changeset(model, params \\ :empty) do
model |> cast(params, @required_fields, @optional_fields)
end
ファイル: web/controllers/user_controller.ex
以下のように編集。
以下のように編集。
def show(conn, %{"id" => id, "select_page" => select_page}) do
user = Repo.get(SampleApp.User, id)
page = SampleApp.Micropost.paginate(user.id, select_page)
changeset = SampleApp.Micropost.new_changeset(
%SampleApp.Micropost{}, %{content: "", user_id: user.id})
if page do
render(conn, "show.html",
user: user,
posts: page.entries,
current_page: page.page_number,
total_pages: page.total_pages,
page_list: Range.new(1, page.total_pages),
changeset: changeset)
else
conn
|> put_flash(:error, "Invalid page number!!")
|> render("show.html", user: user, posts: [])
end
end
ファイル: web/templates/user/show.html.eex
以下のソースコードを最後に追加。
以下のソースコードを最後に追加。
<%= alias SampleApp.LayoutView %>
<h2>User profile</h2>
<div style="float: left; margin-top: 20px; margin-right: 20px;">
<img src="<%= get_gravatar_url(@user) %>" class="gravatar">
<h2><%= @user.name %></h2>
</div>
<div style="clear: right; margin-left: 150px;">
<%= form_for @changeset, micropost_path(@conn, :create), fn f -> %>
<%= if f.errors != [] do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below:</p>
<ul>
<%= for {attr, message} <- f.errors do %>
<li><%= humanize(attr) %> <%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= hidden_input f, :user_id %>
<div class="form-group">
<label>Content</label>
<%= textarea f, :content, class: "form-control" %>
</div>
<div class="form-group">
<%= submit "Post", class: "btn btn-primary" %>
</div>
<% end %>
</div>
<div style="clear: left;">
<%= link "Edit", to: user_path(@conn, :edit, @user), class: "btn btn-default btn-xs" %>
<%= link "Delete", to: user_path(@conn, :delete, @user), method: :delete, class: "btn btn-danger btn-xs" %>
</div>
<div style="float: right; margin-right: 50px;">
<h2>Microposts</h2>
<%= if !is_empty_list?(@posts) do %>
<h2>
<%= for post <- @posts do %>
<li style="padding: 10px 0; border-top: 1px solid #e8e8e8;"><%= post.content %> <%= post.inserted_at %></li>
<% end %>
</h2>
<%= render "pagination.html",
action: user_path(@conn, :show, LayoutView.current_user(@conn).id),
current_page: @current_page,
page_list: @page_list,
total_pages: @total_pages %>
<% end %>
</div>
ファイル: web/controllers/micropost_controller.ex
以下のように編集。
以下のように編集。
plug :scrub_params, "micropost" when action in [:create]
def create(conn, %{"micropost" => micropost_params}) do
changeset = SampleApp.Micropost.changeset(%SampleApp.Micropost{}, micropost_params)
if changeset.valid? do
Repo.insert(changeset)
conn = put_flash(conn, :info, "Post successfully!!")
else
conn = put_flash(conn, :error, "Post failed!!")
end
action = "#{user_path(conn, :show, conn.assigns[:current_user].id)}?select_page=1"
redirect(conn, to: action)
end
これで画面から投稿できるようになった。
Delete of Micropost
マイクロポストの削除機能を実装しましょう。
Deleteアクションの実装です。
Deleteアクションの実装です。
ファイル: web/controllers/micropost_controller.ex
以下のように編集。
以下のように編集。
def delete(conn, %{"id" => id}) do
micropost = Repo.get(SampleApp.Micropost, id)
Repo.delete(micropost)
action = "#{user_path(conn, :show, conn.assigns[:current_user].id)}?select_page=1"
conn
|> put_flash(:info, "Micropost deleted successfully.")
|> redirect(to: action)
end
ファイル: web/templates/user/show.html.eex
削除のリンクを追加。
削除のリンクを追加。
<%= for post <- @posts do %>
<li style="padding: 10px 0; border-top: 1px solid #e8e8e8;">
<%= post.content %>
<%= post.inserted_at %>
<%= link "Delete", to: micropost_path(@conn, :delete, post), method: :delete, class: "btn btn-danger btn-xs" %>
</li>
<% end %>
Speaking to oneself
フィードですが、ここでは実装しません。
Tutorialと別枠でお知らせとRSSといった形でフィードを実装しようと思います。
(それだけで、割と文字数食うのため)
Tutorialと別枠でお知らせとRSSといった形でフィードを実装しようと思います。
(それだけで、割と文字数食うのため)
Tutorialが早く終わることを祈って下さい。
そういえば、SQLインジェクション対策してませんね。
Ecto.Queryを使って自分でQueryを記述する時は、preparedがありましたね。
Ectoの中で上手く変換している気がします。
Ecto.Queryを使って自分でQueryを記述する時は、preparedがありましたね。
Ectoの中で上手く変換している気がします。
確認のため、SQL(select、insert)を入力してみましたが、
ただの文字列として退避されるみたいですね。
(予想通り~)
ただの文字列として退避されるみたいですね。
(予想通り~)
これで第十章は終わり。後はまとめ記事ですね。
has_manyとbelongs_toの機能を全く使ってないことに気付く。
あれを上手く使うのはどうすればいいんだろうか・・・
has_manyとbelongs_toの機能を全く使ってないことに気付く。
あれを上手く使うのはどうすればいいんだろうか・・・
どうでもいいことなんですけど、
何故かdeleteアクションのソースコードだけハイライトが付かない・・・
何故かdeleteアクションのソースコードだけハイライトが付かない・・・