I have a list view where various actions modify an initial list to be displayed. Initially I was duplicating all the logic for this filtering in every action, which worked fine but resulted in a lot of duplicated code like this:
def handle("some_action", _, socket) do
some_assigns = do_some_action
|> apply_some_filter
|> another_filter
socket = socket
|> assign(:some_assigns, some_assigns)
{:no_reply, socket}
end
So I thought I would refactor like so:
def render(assigns) do
filtered_assigns = assigns
|> apply_some_filter
|> another_filter
MyView.render("list", assigns |> Map.put(:filtered_assigns, filtered_assigns))
end
def handle("some_action", _, socket) do
some_assigns = do_some_action
socket = socket
|> assign(:some_assigns, some_assigns)
{:no_reply, socket}
end
This appeared to work at first, insofar as @filtered_assigns was available in the template and filtered corrected, but when I tried calling some_action it no longer updated the template, even though I verified the value of the assign was updated in the render function itself. So, e.g., Enum.count(@filtered_assigns) returned 2, but the template still included 3 items.
So, instead I moved the filters to a ‘helper’ method in MyView instead, and everything worked perfectly with no change in the filter logic itself.
I’m fine with storing that kind of logic in the view rather than modifying assigns in render, but I didn’t see anything in the docs that suggested I shouldn’t be able to do the latter. What I am I missing? I assume the assign function does something internally that Map.put doesn’t?






















