What is defeating me today:
I want a component, included from a layout template, to have access to conn and/or assigns
What I am doing:
- Add a plug to the browser pipeline that takes information from the conn session and puts it into the assigns map.
user = get_session(conn, :current_user)
conn = assign(conn, :avatar, user.avatar)
conn = assign(conn, :userid, user.id)
So far so good; if I then access this from a controller-driven template, we’re happy campers.
However, in components included from a layout template, assigns does NOT contain these values, and instead contains only %{__changed__: nil}
Sequentially, via logging, I can see that:
- The plug runs, and assigns the values, which are viewable in the conn struct.
- They layout component renders, but
assigns
at this point has the__changed__
value only - The controller renders, at which point
assigns
is back to what I expected it to be.
So: something is shadowing assigns for the layout/component sequence? Where does that come from?
I presume this is a bug in my code, but I am not even sure where to look for it.
UPDATE – none of this is for Live View; this is all layout / controller driven content. Much of the prior conversations I have been able to find pertain to debugging live view interactions.
UPDATE – so, I have come to understand that “assigns” for a component is only what is directly passed in from the parent template:
<.account_widget />
Which is implemented by a module with method:
def account_widget(assigns) do
~H"""
<div><%= @avatar %></div>
"""
end
Only gets paramaters passed into it from the dot-notation, which in this case does not include @avatar
– even though that data IS on the assigns portion of the conn struct.
So!
I can either pass the specific data I want down the “call stack” of template inclusion, from the point where it IS available – UGLY! –
OR
I can obtain the conn object from the component module? Is this possible? It certainly seems like it should be, but it’s not obvious how. Simply importing Plug.Conn does not seem sufficient. Thoughts on best practice here? This doesn’t seem like it should be such a difficult scenario, but other than doing the ugly thing, I’m a bit baffled.
UPDATE #3
So, I sort of successfully implemented the ugly approach, but it gets uglier when an attribute is not available: passing a nil value down the inclusion chain does not pass the compiler test.
Some of the components in the chain are pure templates, no explicit module in which to handle alternate attribute values or set defaults.
So, not only does it make the component NOT self contained, but it would force all kinds of hinky logic up the inclusion chain.
There MUST be a way to access the conn struct from a component! Or else I am really using this framework in the wrong way.