Home Posts Tags Post Search Tag Search

Post 32

Blog Site 03 - Updates to make it feel better

Published on: 2025-06-01 Tags: elixir, Blog, Side Project, Ecto, Authorization, Fly, Deployment
Today I wanted to change these things on my blog site:
1. Only I can make a post but anyone can add comments.
2. Add in a better home page to tell my story.
3. Change the look of the posts.
4. Change the look of the post index.
5. Change the links that are seen when: not logged in, logged in, an admin.

1. Add Admin to the users.
This required a few things that needed to be taken care of. First and foremost I needed to add a admin to the user table to check for. 

mix ecto.gen.migration add_admin_to_users 

This will add and other migration

def change do
  alter table(:users) do
    add :admin, :boolean, default: false, null: false
  end
end

This will alter the table so that we can add in a admin colmun

mix ecto.migrate

This will update the database.

Once that was done I needed to change the user schema
def registration_changeset(user, attrs, opts \\ []) do
    user
    |> cast(attrs, [:email, :password, :admin]) # added in the :admin
    |> validate_email(opts)
    |> validate_password(opts)
  end

Now we need to be sure that things that need you to be an Admin will have the check

plug :require_admin when action in [:new, :create, :edit, :update, :delete] 
# put at the top of any page that needs admin requirement

defp require_admin(conn, _opts) do
  if conn.assigns.current_user && conn.assigns.current_user.admin do
    conn
  else
    conn
    |> put_flash(:error, "Unauthorized")
    |> redirect(to: Routes.page_path(conn, :index))
    |> halt()
  end
end
This is the plug utilization.

Okay now we have the tests and admin column we now need to make sure that a user can be set by the admin.

def update_admin(%User{} = user) do
  user
  |> Ecto.Changeset.change(%{admin: true})
  |> Repo.update()
end

This is a very brute force method as it will just take a user and make them an Admin. As you will only be able to run this as someone that owns the site it will work.

Okay so Ill go over this real quick in 2 ways:
On your own localhost:
iex -S mix phx.server # To get in the server with the iex console
user = Blog.Accounts.get_user!(1) # Get the user
Blog.Accounts.update_admin(user) # Make them an admin

On your fly.io
fly ssh console # Get into the fly console
app/bin/blog remote # Get into the app
Blog.Accounts.get_user!(1)
|> Blog.Accounts.update_admin()

Now this is assuming that you have run the migration or the recent deployment ran a migration. Just in case you haven't done that here is those steps:
fly ssh console -C "/app/bin/blog eval 'Blog.Release.migrate()'"

This should run the deployment.

2. Add a better home page.
This is a bit more general but in the end I made sure to have some references to the work that I have done and added some better styling.

Here is a link,
<a href="https://www.hackerrank.com/" target="_blank" style="color: #007acc; text-decoration: none;">HackerRank</a>,

Here is a link that has a "link" icon
🔗 <a href="https://game-site.fly.dev/" target="_blank" style="color: #007acc; font-weight: bold;">Game Site</a><br>

3. Change the look of the posts.
This was a small but having less on the screen can help with the clarity. Also I'll say this now any time you want to be sure that an item will only be seen by an admin you can add.

<%= if @current_user.admin do %>
    ...
<% end %>

# This will check to be sure that the person is an Admin.

I also wanted to have the tags, and published on smaller and on the same line.
<div class="max-w-6xl mx-auto p-8 bg-white shadow rounded">
  <!-- Title -->
  <div>
    <h1 class="text-3xl font-bold text-gray-900 mb-2">{@post.title}</h1>
    <div class="text-sm text-gray-500 flex flex-wrap gap-4">
      <span>Published on: <span class="text-gray-700">{@post.published_on}</span></span>
      <span>Tags: 
        <span class="text-gray-700">
          <%= Enum.map(@post.tags, & &1.name) |> Enum.join(", ") %>
        </span>
      </span>
    </div>
  </div>

4. This is an other one that took some more padding, and some other small changes.

5. One more time I'll post it here again, if you want to check for an Admin (html) you simply can add this around an html item.
<%= if @current_user.admin do %>
    ...
<% end %>