elt547

elt547

Looking for help with context implementation (for polymorphic associations)

Many of my schemas can be considered to have a Feed, so I followed the many-to-many recommendation for polymorphic associations.

I want to be able to list feed items, create posts of different types, delete posts of different types from a single interface. My initial thought was to make a Feed protocol, so I’ve been going down this path:

defmodule Hydroplane.Feeds do
  alias Hydroplane.Feeds.Feed

  def list_feed_items(feedable) do
    Feed.list_posts(feedable) ++ Feed.list_polls(feedable)
  end

  def create_post(feedable, author, attrs) do
    Feed.create_post(feedable, author, attrs)
  end
end

And the Feed protocol is here:

defprotocol Hydroplane.Feeds.Feed do
  def list_posts(feedable)
  def list_polls(feedable)
  def create_post(feedable, author, attrs)
end

defimpl Hydroplane.Feeds.Feed, for: Hydroplane.Initiatives.Initiative do
  import Ecto.Query
  alias Ecto.Multi

  alias Hydroplane.Repo
  alias Hydroplane.Initiatives.Initiative
  alias Hydroplane.Feeds.{Post, Poll}

  def list_posts(initiative) do
    query =
      from(p in Post,
        join: ip in "initiative_posts",
        on: p.id == ip.post_id,
        join: i in Initiative,
        on: i.id == ip.initiative_id,
        where: i.id == ^initiative.id
      )

    query
    |> Repo.all()
    |> Repo.preload(:author)
  end

  def list_polls(initiative) do
    query =
      from(p in Poll,
        join: ip in "initiative_polls",
        on: p.id == ip.poll_id,
        join: i in Initiative,
        on: i.id == ip.initiative_id,
        where: i.id == ^initiative.id
      )

    query
    |> Repo.all()
    |> Repo.preload(:author)
  end

  def create_post(initiative, author, attrs) do
    result =
      Multi.new()
      |> Multi.insert(:post, Post.changeset(%Post{author: author}, attrs))
      |> Multi.insert(:association, fn %{post: post} -> end)
      |> Repo.transaction()
      # Stuff like this is where it can start to get really messy
  end
end

The absolute JANK that I’m creating, basically having to fully implement Feed for each feedable item makes me think this is the wrong approach. It seems crazy to implement everything differently when the only thing that changes is how I interact with the join table.

In Ruby the obvious way to solve this would be through metaprogramming, is that the proper route here? What’s a better way to do this? I’m sure there are several.

First Post!

al2o3cr

al2o3cr

Assuming the Initiative schema has the needed many_to_many associations, these functions could be shorter:

  def list_posts(initiative) do
   Ecto.assoc(initiative, :posts)
    |> Repo.all()
    |> Repo.preload(:author)
  end

  def list_polls(initiative) do
    Ecto.assoc(initiative, :polls)
    |> Repo.all()
    |> Repo.preload(:author)
  end

You could try to DRY this out further, but presumably Poll and Post are different somehow that might require different preloads.

Ecto.build_assoc sounds promising for the last part.

Where Next?

Popular in Questions Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement