Search code examples
elixirphoenix-frameworkectochangeset

Modifying a list of structs in Phoenix


I have a blog with a backend showing a list of Posts. Each Post has a publish_on value which is a datetime -- if the current time is later than publish_on, the Post is active (Post has a boolean virtual field called active).

When I query the Repo for a list of Posts, I'd like to go through the list, and set Post's active to true if the current time is after publish_on.

What is the most "Elixirian" way to do this? (Also, what is the Elixir community's version of "Pythonic"?)

models/post.ex

defmodule MyApp.Post do
  use MyApp.Web, :model

  schema "posts" do
    field :title, :string
    field :content, :text
    field :publish_on, Ecto.DateTime
    field :active, :boolean, virtual: true, default: false

    timestamps()
  end

controllers/post_controller.ex

MyApp.PostController
  def index(conn, _params) do
    query = from p in Post,
    posts = Repo.all(query)

    ###I assume some kind of mapping goes here

    render(conn, "index.html", posts: posts)
  end

templates/post/index.html.eex

<table class="table">
<%= for post <- @posts do %>
    <%= if post.active do %>
      <tr class="published">
    <% else %>
      <tr class="unpublished">
    <% end %>

Solution

  • I'd go through the posts using for, compare DateTime.utc_now with post.publish_on using DateTime.compare, and if it's :gt, set active to true:

    posts = Repo.all(query)
    
    now = DateTime.utc_now
    
    posts = for post <- posts do
      case DateTime.compare(now, post.publish_on) do
        :gt -> %{post | active: true}
        _ -> post
      end
    end