What to do when you have to add a new parameter based on the result you get from a Service?

Hello folks!

I have a question about how to deal with Context, in particular I see that from the perspective of controller tests all the keys of the params are passed as strings, while from the perspective of context|model tests we pass all the params keys as atoms.

That’s not make a big difference cause what matter is that all the keys of a map have to be of the same type, but …

I need to use a Service inside one of my Context so that based on the result I get from it I need to add a new key, value pair in the parameters map.

The problem I have is that “I don’t know” if I have to put the key as an atom or as a string.

So, I end up with this solution, but I bet that there is a better way to deal with it. In short, I created an helper function add_param_to that in somehow can understand if to deal with atoms or strings.

Thank you so much for all the feedback!

Here it is my pseudo code:

defmodule Something.Blogs do

  alias Something.Post
  alias Something.{CalendarService, CalendarEvent}

  def create_blog_post(attrs, podcast, calendar_service \\ CalendarService) do
    event_start = Map.get(attrs, :recorded_at)

    attrs = case calendar_service.create(CalendarEvent.build_for(podcast, event_start)) do
      {:ok, event_id} -> add_param_to(attrs, "calendar_event_id", event_id)
      {:error, _message} -> attrs
    end

    Post.insert_changeset(attrs)
    |> Repo.insert
  end

  defp add_param_to(attrs, key, value) do
    [head|_] = Map.keys(attrs)
    add_param_to(attrs, key, value, is_atom(head))
  end

  defp add_param_to(attrs, key, value, is_atom) when is_atom do
    Map.put(attrs, String.to_atom(key), value)
  end
  defp add_param_to(attrs, key, value, _is_atom) do
    Map.put(attrs, key, value)
  end
end

I usually try to avoid changing anything in attrs or params. I “pre-populate” schemas’ structs instead.

  def create_blog_post(attrs, podcast, calendar_service \\ CalendarService) do
    event_start = Map.get(attrs, :recorded_at) || Map.get(attrs, "recorded_at")

    event_id = case calendar_service.create(CalendarEvent.build_for(podcast, event_start)) do
      {:ok, event_id} -> event_id
      {:error, _message} -> nil
    end
    
    %Post{calendar_event_id: event_id} 
    |> Post.insert_changeset(attrs)
    |> Repo.insert
  end
2 Likes

Thank you so much for your answer, it seems to be more reasonable :slightly_smiling_face: