Skip to content

Commit fcbdffc

Browse files
adds live post comments
1 parent dbd8400 commit fcbdffc

File tree

13 files changed

+356
-56
lines changed

13 files changed

+356
-56
lines changed

lib/reddit/comments.ex

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
defmodule Reddit.Comments do
2+
@moduledoc """
3+
The Comments context.
4+
"""
5+
import Ecto
6+
import Ecto.Query, warn: false
7+
alias Reddit.Repo
8+
9+
alias Reddit.Comments.Comment
10+
11+
@doc """
12+
Returns the list of comments.
13+
14+
## Examples
15+
16+
iex> list_comments()
17+
[%Comment{}, ...]
18+
19+
"""
20+
def list_comments do
21+
Repo.all(Comment)
22+
end
23+
24+
@doc """
25+
Gets a single comment.
26+
27+
Raises `Ecto.NoResultsError` if the Comment does not exist.
28+
29+
## Examples
30+
31+
iex> get_comment!(123)
32+
%Comment{}
33+
34+
iex> get_comment!(456)
35+
** (Ecto.NoResultsError)
36+
37+
"""
38+
def get_comment!(id), do: Repo.get!(Comment, id)
39+
40+
@doc """
41+
Creates a comment.
42+
43+
## Examples
44+
45+
iex> create_comment(%{field: value})
46+
{:ok, %Comment{}}
47+
48+
iex> create_comment(%{field: bad_value})
49+
{:error, %Ecto.Changeset{}}
50+
51+
"""
52+
def create_comment(user, post, comment) do
53+
c = Ecto.build_assoc(user, :comments, comment)
54+
Ecto.build_assoc(post, :comments, c)
55+
|> Repo.insert()
56+
end
57+
58+
@doc """
59+
Updates a comment.
60+
61+
## Examples
62+
63+
iex> update_comment(comment, %{field: new_value})
64+
{:ok, %Comment{}}
65+
66+
iex> update_comment(comment, %{field: bad_value})
67+
{:error, %Ecto.Changeset{}}
68+
69+
"""
70+
def update_comment(%Comment{} = comment, attrs) do
71+
comment
72+
|> Comment.changeset(attrs)
73+
|> Repo.update()
74+
end
75+
76+
@doc """
77+
Deletes a comment.
78+
79+
## Examples
80+
81+
iex> delete_comment(comment)
82+
{:ok, %Comment{}}
83+
84+
iex> delete_comment(comment)
85+
{:error, %Ecto.Changeset{}}
86+
87+
"""
88+
def delete_comment(%Comment{} = comment) do
89+
Repo.delete(comment)
90+
end
91+
92+
@doc """
93+
Returns an `%Ecto.Changeset{}` for tracking comment changes.
94+
95+
## Examples
96+
97+
iex> change_comment(comment)
98+
%Ecto.Changeset{data: %Comment{}}
99+
100+
"""
101+
def change_comment(%Comment{} = comment, attrs \\ %{}) do
102+
Comment.changeset(comment, attrs)
103+
end
104+
end

lib/reddit/comments/comment.ex

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
defmodule Reddit.Comments.Comment do
2+
use Ecto.Schema
3+
import Ecto.Changeset
4+
5+
alias Reddit.Users.User
6+
alias Reddit.Community.Post
7+
8+
schema "comments" do
9+
field :body, :string
10+
belongs_to :user, User
11+
belongs_to :post, Post
12+
13+
timestamps()
14+
end
15+
16+
@doc false
17+
def changeset(comment, attrs) do
18+
comment
19+
|> cast(attrs, [:body])
20+
|> validate_required([:body])
21+
end
22+
end

lib/reddit/community.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,4 @@ defmodule Reddit.Community do
102102
def change_post(%Post{} = post, attrs \\ %{}) do
103103
Post.changeset(post, attrs)
104104
end
105-
106105
end

lib/reddit/community/post.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,25 @@ defmodule Reddit.Community.Post do
44

55
alias Reddit.Category.Community
66
alias Reddit.Users.User
7+
alias Reddit.Comments.Comment
78

89
schema "posts" do
910
field :body, :string
1011
field :title, :string
1112
field :upvotes, :integer, default: 0
1213
field :downvotes, :integer, default: 0
13-
field :comments, :integer, default: 0
14+
field :comments_count, :integer, default: 0
1415
belongs_to :community, Community
1516
belongs_to :user, User
17+
has_many :comments, Comment
1618

1719
timestamps()
1820
end
1921

2022
@doc false
2123
def changeset(post, attrs) do
2224
post
23-
|> cast(attrs, [:title, :body, :upvotes, :downvotes, :comments])
25+
|> cast(attrs, [:title, :body, :upvotes, :downvotes, :comments_count])
2426
|> validate_required([:title, :body])
2527
end
2628
end

lib/reddit/users/user.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ defmodule Reddit.Users.User do
1212
alias Reddit.Category.Community
1313
alias Reddit.Community.Subscription
1414
alias Reddit.Community.Post
15+
alias Reddit.Comments.Comment
1516

1617
schema "users" do
1718
pow_user_fields()
@@ -23,6 +24,7 @@ defmodule Reddit.Users.User do
2324
has_many :communities, Community
2425
has_many :subscriptions, Subscription
2526
has_many :posts, Post
27+
has_many :comments, Comment
2628

2729
timestamps()
2830
end

lib/reddit_web/controllers/post_controller.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule RedditWeb.PostController do
99
alias Reddit.Repo
1010

1111
def show(conn, %{"id" => id}) do
12-
post = CommunityPost.get_post!(id) |> Repo.preload(:community)
12+
post = CommunityPost.get_post!(id) |> Repo.preload([:community, :comments])
1313
render(conn, :show, post: post, community: post.community)
1414
end
1515

lib/reddit_web/live/comments_live.ex

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
defmodule RedditWeb.CommentsLive do
2+
use RedditWeb, :live_view
3+
4+
alias Reddit.Comments
5+
alias Reddit.Comments.Comment
6+
alias Reddit.Repo
7+
alias Reddit.Users.User
8+
alias Reddit.Community
9+
10+
def mount(_params, %{"post" => post, "user_id" => user_id}, socket) do
11+
changeset = Comments.change_comment(%Comment{})
12+
comments = post.comments |> Repo.preload(:user)
13+
14+
socket =
15+
assign(socket,
16+
u_id: user_id,
17+
p_id: post.id,
18+
comments: comments,
19+
changeset: changeset
20+
)
21+
22+
{:ok, socket, temporary_assigns: [comments: []]}
23+
end
24+
25+
def handle_event("save", %{"comment" => params}, socket) do
26+
user = Repo.get!(User, params["u_id"])
27+
post = Community.get_post!(params["p_id"])
28+
comment = params |> Map.new(fn {k, v} -> {String.to_atom(k), v} end)
29+
case Comments.create_comment(user, post, comment) do
30+
{:ok, comment} ->
31+
comment = comment |> Repo.preload(:user)
32+
socket =
33+
update(
34+
socket,
35+
:comments,
36+
fn comments -> [comment | comments] end
37+
)
38+
39+
changeset = Comments.change_comment(%Comment{})
40+
41+
socket = assign(socket, changeset: changeset)
42+
43+
:timer.sleep(500)
44+
45+
{:noreply, socket}
46+
47+
{:error, %Ecto.Changeset{} = changeset} ->
48+
socket = assign(socket, changeset: changeset)
49+
{:noreply, socket}
50+
end
51+
end
52+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<div id="comments" phx-update="append">
2+
<%= for comment <- @comments do %>
3+
<div class="comment" id="<%= comment.id %>">
4+
<%= live_patch comment.user.full_name, to: Routes.user_path(@socket, :profile, comment.user.username) %>
5+
<p><%= comment.body %></p>
6+
</div>
7+
<% end %>
8+
</div>
9+
10+
11+
<h5>Leave a comment</h5>
12+
13+
<%= f = form_for @changeset, "#",
14+
phx_submit: "save" %>
15+
16+
<%= textarea f, :body, class: "form-control" %>
17+
<%= error_tag f, :body %>
18+
19+
<%= hidden_input f, :u_id, value: @u_id %>
20+
<%= hidden_input f, :p_id, value: @p_id %>
21+
22+
<%= submit "Submit Comment", class: "btn btn-success mt-3",
23+
phx_disable_with: "Saving..." %>
24+
</form>

lib/reddit_web/templates/post/show.html.eex

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,58 +11,7 @@
1111

1212
<%= text_to_html(@post.body, [wrapper_tag: :p]) %>
1313

14-
<div id="post-comments">
15-
<div class="comment">
16-
<a href="/u/davidb">David Battersby</a>
17-
<p>Let me know what you guys think.</p>
18-
</div>
19-
<div class="comment">
20-
<a href="/u/moskina">moskina moskina</a>
21-
<p>adasdsad</p>
22-
</div>
23-
<div class="comment">
24-
<a href="/u/moskina">moskina moskina</a>
25-
<p>adasdsadsdasd</p>
26-
</div>
27-
<div class="comment">
28-
<a href="/u/moskina">moskina moskina</a>
29-
<p>adasdsadsdasddasdasd</p>
30-
</div>
31-
<div class="comment">
32-
<a href="/u/testing">test testtest</a>
33-
<p>test test</p>
34-
</div>
35-
</div>
36-
37-
<h5>Leave a comment</h5>
38-
<form
39-
class="new_comment"
40-
id="new_comment"
41-
action="/comments"
42-
accept-charset="UTF-8"
43-
data-remote="true"
44-
method="post"
45-
>
46-
<input
47-
value="1"
48-
type="hidden"
49-
name="comment[post_id]"
50-
id="comment_post_id"
51-
/>
52-
<textarea
53-
placeholder="Your comment goes here"
54-
class="form-control"
55-
name="comment[message]"
56-
id="comment_message"
57-
></textarea>
58-
<input
59-
type="submit"
60-
name="commit"
61-
value="Submit comment"
62-
class="btn btn-success mt-3"
63-
data-disable-with="Submit comment"
64-
/>
65-
</form>
14+
<%= live_render(@conn, RedditWeb.CommentsLive, session: %{"post" => @post, "user_id" => @current_user.id}) %>
6615
</div>
6716
</div>
6817

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
defmodule Reddit.Repo.Migrations.CreateComments do
2+
use Ecto.Migration
3+
4+
def change do
5+
create table(:comments) do
6+
add :body, :text
7+
add :user_id, references(:users, on_delete: :nothing)
8+
add :post_id, references(:posts, on_delete: :nothing)
9+
10+
timestamps()
11+
end
12+
13+
create index(:comments, [:user_id])
14+
create index(:comments, [:post_id])
15+
end
16+
end

0 commit comments

Comments
 (0)