Skip to content

Instantly share code, notes, and snippets.

@joshchernoff
Last active May 4, 2020 20:25
Show Gist options
  • Save joshchernoff/8f49a1ff56623d9dca3e021bdc2e8f3b to your computer and use it in GitHub Desktop.
Save joshchernoff/8f49a1ff56623d9dca3e021bdc2e8f3b to your computer and use it in GitHub Desktop.
LiveView Post Show
# lib/morphic_pro/blog.ex
defmodule MorphicPro.Blog do
...
def get_post!(slug, current_user, options \\ []) do
preload = Keyword.get(options, :preload, [])
Post
|> Repo.by_slug(slug)
|> from(preload: ^preload)
|> Bodyguard.scope(current_user)
|> Repo.one!()
end
...
end
The logs from my console.
[info] GET /posts/foobar
[debug] Processing with Phoenix.LiveView.Plug.show/2
Parameters: %{"slug" => "foobar"}
Pipelines: [:browser]
[
"mount",
%{"slug" => "foobar"},
%{
"_csrf_token" => "...",
"user_token" => ...
},
#Phoenix.LiveView.Socket<
assigns: %{
flash: %{},
live_action: :show,
live_module: MorphicProWeb.PostLive.Show
},
changed: %{},
endpoint: MorphicProWeb.Endpoint,
id: "phx-Fgvs1dGJIPBNOgEC",
parent_pid: nil,
root_pid: nil,
router: MorphicProWeb.Router,
view: MorphicProWeb.PostLive.Show,
...
>
]
[debug] QUERY OK source="users_tokens" db=23.2ms idle=3075.7ms
SELECT u1."id", u1."email", u1."hashed_password", u1."confirmed_at", u1."admin", u1."inserted_at", u1."updated_at" FROM "users_tokens" AS u0 INNER JOIN "users" AS u1 ON u1."id" = u0."user_id" WHERE ((u0."token" = $1) AND (u0."context" = $2)) AND (u0."inserted_at" > $3::timestamp + (-60::decimal::numeric * interval '1 day')) [..., "session", ~U[2020-05-04 20:21:36.666142Z]]
[
"handle_params",
%{"slug" => "foobar"},
"https://localhost:4001/posts/foobar",
#Phoenix.LiveView.Socket<
assigns: %{
current_user: #MorphicPro.Accounts.User<
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
admin: true,
captcha: nil,
captcha_return: nil,
confirmed_at: ~N[2020-04-22 20:51:33],
email: "jchernoff@morphic.pro",
...
>,
flash: %{},
live_action: :show,
live_module: MorphicProWeb.PostLive.Show
},
changed: %{current_user: true},
endpoint: MorphicProWeb.Endpoint,
id: "phx-Fgvs1dGJIPBNOgEC",
parent_pid: nil,
root_pid: nil,
router: MorphicProWeb.Router,
view: MorphicProWeb.PostLive.Show,
...
>
]
[debug] QUERY OK source="posts" db=5.9ms idle=2959.3ms
SELECT p0."id", p0."body", p0."draft", p0."excerpt", p0."published_at", p0."published_at_local", p0."slug", p0."title", p0."large_img", p0."thumb_img", p0."likes_count", p0."tags_string", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."slug" = $1) ["foobar"]
[debug] QUERY OK source="tags" db=12.0ms idle=2928.6ms
SELECT t0."id", t0."name", p1."id" FROM "tags" AS t0 INNER JOIN "posts" AS p1 ON p1."id" = ANY($1) INNER JOIN "post_tags" AS p2 ON p2."post_id" = p1."id" WHERE (p2."tag_id" = t0."id") ORDER BY p1."id" [[12]]
[info] Sent 200 in 46ms
[info] CONNECTED TO Phoenix.LiveView.Socket in 227µs
Transport: :websocket
Serializer: Phoenix.Socket.V2.JSONSerializer
Parameters: %{"_csrf_token" => "...", "vsn" => "2.0.0"}
[
"mount",
%{"slug" => "foobar"},
%{
"_csrf_token" => "...",
"user_token" => ...
},
#Phoenix.LiveView.Socket<
assigns: %{
flash: %{},
live_action: :show,
live_module: MorphicProWeb.PostLive.Show
},
changed: %{},
endpoint: MorphicProWeb.Endpoint,
id: "phx-Fgvs1dGJIPBNOgEC",
parent_pid: nil,
root_pid: #PID<0.683.0>,
router: MorphicProWeb.Router,
view: MorphicProWeb.PostLive.Show,
...
>
]
[debug] QUERY OK source="users_tokens" db=7.2ms idle=3347.1ms
SELECT u1."id", u1."email", u1."hashed_password", u1."confirmed_at", u1."admin", u1."inserted_at", u1."updated_at" FROM "users_tokens" AS u0 INNER JOIN "users" AS u1 ON u1."id" = u0."user_id" WHERE ((u0."token" = $1) AND (u0."context" = $2)) AND (u0."inserted_at" > $3::timestamp + (-60::decimal::numeric * interval '1 day')) [..., "session", ~U[2020-05-04 20:21:37.128194Z]]
[
"handle_params",
%{"slug" => "foobar"},
"https://localhost:4001/posts/foobar",
#Phoenix.LiveView.Socket<
assigns: %{
current_user: #MorphicPro.Accounts.User<
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
admin: true,
captcha: nil,
captcha_return: nil,
confirmed_at: ~N[2020-04-22 20:51:33],
email: "jchernoff@morphic.pro",
...
>,
flash: %{},
live_action: :show,
live_module: MorphicProWeb.PostLive.Show
},
changed: %{current_user: true},
endpoint: MorphicProWeb.Endpoint,
id: "phx-Fgvs1dGJIPBNOgEC",
parent_pid: nil,
root_pid: #PID<0.683.0>,
router: MorphicProWeb.Router,
view: MorphicProWeb.PostLive.Show,
...
>
]
[debug] QUERY OK source="posts" db=11.5ms idle=2211.0ms
SELECT p0."id", p0."body", p0."draft", p0."excerpt", p0."published_at", p0."published_at_local", p0."slug", p0."title", p0."large_img", p0."thumb_img", p0."likes_count", p0."tags_string", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."slug" = $1) ["foobar"]
[debug] QUERY OK source="tags" db=30.8ms queue=0.1ms idle=2214.7ms
SELECT t0."id", t0."name", p1."id" FROM "tags" AS t0 INNER JOIN "posts" AS p1 ON p1."id" = ANY($1) INNER JOIN "post_tags" AS p2 ON p2."post_id" = p1."id" WHERE (p2."tag_id" = t0."id") ORDER BY p1."id" [[12]]
# lib/morphic_pro/blog/post.ex
defmodule MorphicPro.Blog.Post do
...
@behaviour Bodyguard.Schema
def scope(query, %MorphicPro.Accounts.User{admin: true}, _), do: query
def scope(query, _, _), do: MorphicPro.Repo.where_published(query)
...
end
# lib/morphic_pro_web/router.ex
defmodule MorphicProWeb.Router do
use MorphicProWeb, :router
...
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, {MorphicProWeb.LayoutView, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end
...
scope "/", MorphicProWeb do
pipe_through :browser
live "/posts/:slug", PostLive.Show, :show
end
end
# lib/morphic_pro_web/live/post_live/show.ex
defmodule MorphicProWeb.PostLive.Show do
use MorphicProWeb, :live_view
alias MorphicPro.Blog
alias MorphicPro.Blog.Post
alias MorphicPro.Accounts
@impl true
def mount(%{"slug" => slug} = params, session, socket) do
IO.inspect(["mount", params, session, socket])
if connected?(socket),
do: Phoenix.PubSub.subscribe(MorphicPro.PubSub, "post:#{slug}")
if user = session["user_token"] && Accounts.get_user_by_session_token(session["user_token"]) do
{:ok, assign(socket, current_user: user)}
else
{:ok, assign(socket, current_user: nil)}
end
end
@impl true
def handle_params(%{"slug" => slug} = params, session, %{assigns: %{current_user: current_user}} = socket) do
IO.inspect(["handle_params", params, session, socket])
# How do I render a 404 with LV?
# is the (Ecto.NoResultsError) expected at least one result but got none in query: handled?
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:post, Blog.get_post(slug, current_user, preload: [:tags]))}
end
@impl true
def render(assigns) do
~L"""
...
"""
end
defp page_title(:show), do: "Show Post"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment