<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="386859" data-post-id="386859">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>(4) Discriminated union errors don’t tell you which variant was matched</p>
<p>First, simple case: field name is unique, you can guess more or less easily:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">schema = Zoi.discriminated_union(:type, [
  Zoi.map(%{type: Zoi.literal("credit_card"), cvv: Zoi.string() |&gt; Zoi.min(3)}),
  Zoi.map(%{type: Zoi.literal("wallet"), wallet_id: Zoi.string()})
])

# input: %{"type" =&gt; "credit_card", "cvv" =&gt; "1"}
# error: %Zoi.Error{path: [:cvv], code: :greater_than_or_equal_to}
# you can guess "credit_card" because only that variant has :cvv. Not ideal but it works.
</code></pre>
<p>Secondly, ambiguous case: same field name in multiple variants, you can’t guess where it is:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">schema = Zoi.discriminated_union(:type, [
  Zoi.map(%{type: Zoi.literal("retail"), amount: Zoi.integer() |&gt; Zoi.min(1)}),
  Zoi.map(%{type: Zoi.literal("refund"), amount: Zoi.integer() |&gt; Zoi.max(0)})
])

# input: %{"type" =&gt; "retail", "amount" =&gt; 0}
# error: %Zoi.Error{path: [:amount], code: :greater_than_or_equal_to}
# which variant? Both have :amount. No way to tell programmatically.
</code></pre>
<p>Zoi resolved the variant internally (it validated <code>amount</code> against the <code>retail</code> map) but that information is discarded and not visible to a user of the library. In the ambiguous case, a consumer (or library) building error messages or routing errors to the right form section has no machine-readable way to determine which variant failed.</p>
<p>Can you include the matched variant somewhere? Either in the path f.ex. <code>[:retail, :amount]</code>, or as an extra key in issue opts f.ex. <code>variant: "retail"</code>?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386859" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/zoi-schema-validation-library-inspired-by-zod/72108/52">Post #51</a>
	                </div>
	            </div>
              <div id="likers-container-386859" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386859"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #51"></div>
  </section>
</div>
    <div class="postbit" id="386862" data-post-id="386862">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>(5) <code>coerce: true</code> inheritance</p>
<p>This might be a bit of an XY problem potentially but please work with me here.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Zoi.map(%{
  address: Zoi.map(%{zip: Zoi.string()}, coerce: true),
  payment: Zoi.discriminated_union(:type, [...], coerce: true)
}, coerce: true)
</code></pre>
<p>Repeated 3 times.</p>
<p>Basically if you have nested types that must all be coerced, the schema gets a bit repetitive with all the <code>coerce: true</code> lines. Not the end of the world but a touch annoying.</p>
<p>So could this be automatically “inherited” (which I agree is a bit off) or maybe allow some extra opt f.ex. <code>inherit_coerce: true</code> at the root level? <img src="https://forum.elixirforum.com/images/emoji/apple/thinking.png?v=15" title=":thinking:" class="emoji" alt=":thinking:" loading="lazy" width="20" height="20"> Unsure how would I address this but it’s a DX item and we could discuss it until we arrive at something we’re happy with.</p>
<p>Mind you, I am quite fine with that <em>not</em> being addressed, just asking if you are open to make it a touch more convenient?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386862" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/zoi-schema-validation-library-inspired-by-zod/72108/53">Post #52</a>
	                </div>
	            </div>
              <div id="likers-container-386862" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386862"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #52"></div>
  </section>
</div>
    <div class="postbit" id="386863" data-post-id="386863">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Finally, an even smaller DX ask:</p>
<p>(6) <code>Zoi.refine</code> function capture</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># Currently: MFA tuple required in module attributes:
@schema Zoi.map(%{...}) |&gt; Zoi.refine({__MODULE__, :validate_codependency, []})

# What I'd also like to have: a function capture:
@schema Zoi.map(%{...}) |&gt; Zoi.refine(&amp;validate_codependency/1)
</code></pre>
<p>Currently, <code>&amp;fun/1</code> only works at runtime (inside def), not in <code>@attrs</code>. But even at runtime, <code>refine</code> expects 2-arity (parsed, opts), so a 1-arity capture needs wrapping.</p>
<p>Minor ask. Just something I noticed while I was prototyping test schemas.</p>
<p>That’s all. Sorry for temporarily monopolizing the thread.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386863" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/zoi-schema-validation-library-inspired-by-zod/72108/54">Post #53</a>
	                </div>
	            </div>
              <div id="likers-container-386863" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386863"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #53"></div>
  </section>
</div>
    <div class="postbit" id="386876" data-post-id="386876">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="phcurado" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/120/39030_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  phcurado
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dimitarvp" data-post="49" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>I’ve noticed in your own draft PR you are using <code>Zoi.Context</code> which has all the data and I want to update my PR (<span class="hashtag-raw">#162</span>) to use it – but wanted to first ask you: is this a “blessed” / public API one can rely on?</p>
</blockquote>
</aside>
<p>Yes! It’s public API and it’s documented <a href="https://hexdocs.pm/zoi/Zoi.Context.html" rel="noopener nofollow ugc">here</a>. I had to create the context for solving this exactly problem: Partial parsing information which was required when implementing phoenix forms integration. I recommend to always use the <code>Context</code> for parsing if you need more information and metadata of the parsed data, so it ends up being really useful for integrating with other libraries or even creating your own library on top of zoi.</p>
<aside class="quote no-group" data-username="dimitarvp" data-post="50" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<pre data-code-wrap="elixir"><code class="lang-elixir">{"invalid enum value: expected one of %{values}", [type: :enum, values: ["USD", "EUR", "GBP"]]}
</code></pre>
</blockquote>
</aside>
<p>That’s fair, I think I’ve done this way because I also merge the error string to generate human readable messages, I will give a check on this one.</p>
<aside class="quote no-group" data-username="dimitarvp" data-post="51" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>(3) Zoi produces identical codes for different types</p>
</blockquote>
</aside>
<p>The followup question I would do is: Why do you need the errors to be exactly like Ecto? We could return <code>Zoi</code> errors into a Changeset struct. Not everything will be “translatable” since it’s different libraries. For example <code>Zoi</code> don’t have atom types, the types are modules and implemented with protocols. Same goes for validations, they are protocols or plain functions which makes then flexible. <code>Zoi</code> have support for adding custom metadata to errors but I know it will not be enough for this use case if you want to preserve the way ecto behaves. We could also match the <code>zoi</code> modules or type structs to <code>ecto</code> types (example: <code>Zoi.Types.String</code> means <code>:string</code> in ecto) since the implementation is fundamentally different.</p>
<aside class="quote no-group" data-username="dimitarvp" data-post="52" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>(4) Discriminated union errors don’t tell you which variant was matched</p>
</blockquote>
</aside>
<p>This is consistent with Zod library although the behavior can be changed here. For instance it’s possible to match with the <code>input["type"]</code> you send during parsing to fetch this info but it makes sense to ahve more info in the error struct (or use context <code>ctx.input[:type]</code>).</p>
<aside class="quote no-group" data-username="dimitarvp" data-post="53" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>(5) <code>coerce: true</code> inheritance</p>
</blockquote>
</aside>
<p>I agree, I built the <a href="https://hexdocs.pm/zoi/Zoi.Schema.html" rel="noopener nofollow ugc">schema module</a> for this, you can traverse the schema and add metadata that should apply for all types.</p>
<aside class="quote no-group" data-username="dimitarvp" data-post="54" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>(6) <code>Zoi.refine</code> function capture</p>
</blockquote>
</aside>
<p>I think this already works, I have tests for one argument refinements <a href="https://github.com/phcurado/zoi/blob/main/test/zoi_test.exs#L4277-L4277" rel="noopener nofollow ugc">here</a>.</p>
<p>Good feedback thank you. I will analyze in more detail each topic and will see areas for improving. Overall if requires too many changes we can always build another library that integrates <code>zoi</code> and <code>ecto</code> that handles the edge cases since both libraries have their own architecture.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386876" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/zoi-schema-validation-library-inspired-by-zod/72108/55">Post #54</a>
	                </div>
	            </div>
              <div id="likers-container-386876" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386876"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #54"></div>
  </section>
</div>
    <div class="postbit" id="386881" data-post-id="386881">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>Yes! It’s public API and it’s documented <a href="https://hexdocs.pm/zoi/Zoi.Context.html" rel="noopener nofollow ugc">here</a>.</p>
</blockquote>
</aside>
<p>Awesome, thanks! I was not sure whether it’s not temporary or unintended for general use. Good to know I can use it.</p>
<p>I have updated the PR to use <code>Zoi.Context</code> but hit an issue with arrays:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">schema = Zoi.map(%{
  items: Zoi.array(
    Zoi.map(%{sku: Zoi.string(), qty: Zoi.integer() |&gt; Zoi.positive()}, coerce: true)
  )
}, coerce: true)

input = %{"items" =&gt; [
  %{"sku" =&gt; "A", "qty" =&gt; 5},
  %{"sku" =&gt; "B", "qty" =&gt; -1},
  %{"sku" =&gt; "C", "qty" =&gt; 10}
]}

ctx = Zoi.Context.new(schema, input) |&gt; Zoi.Context.parse()

ctx.errors
# =&gt; [%Zoi.Error{path: [:items, 1, :qty], ...}]
# Error is at index 1 -- good.

ctx.parsed.items
# =&gt; [%{sku: "A", qty: 5}, %{sku: "C", qty: 10}]
# Only 2 items! Item at index 1 was dropped.
# We can't tell that %{sku: "C"} was originally at index 2.

# Desired: either preserve position with nil placeholder:
# =&gt; [%{sku: "A", qty: 5}, nil, %{sku: "C", qty: 10}]
# Or include partial data for errored items:
# =&gt; [%{sku: "A", qty: 5}, %{sku: "B"}, %{sku: "C", qty: 10}]
</code></pre>
<p>This would be great for forms if you are up for changing it. Or you can just have Zoi return integer-keyed maps? Up to you.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>That’s fair, I think I’ve done this way because I also merge the error string to generate human readable messages, I will give a check on this one.</p>
</blockquote>
</aside>
<p>Thank you, it would really help IMO. Especially when wanting to return structured API responses, which is my case.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>The followup question I would do is: Why do you need the errors to be exactly like Ecto?</p>
</blockquote>
</aside>
<p>I like Zoi better, let’s have that out of the way – I need the full translation because I can’t just modify a big project to only use Zoi strictly everywhere (as much as I would like to). So I do need Ecto parity. The PR is already at least 90% there, if not 99% even. I am wondering if we can go to 100%.</p>
<p>On a more general note, having non-ambiguous error structs / keyword lists seems like a win to me for any such library.</p>
<p>Up to you as a maintainer of course. I’ll hack it in my work code if you are uncertain whether you want to change Zoi here.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>This is consistent with Zod library although the behavior can be changed here. For instance it’s possible to match with the <code>input["type"]</code> you send during parsing to fetch this info but it makes sense to ahve more info in the error struct (or use context <code>ctx.input[:type]</code>).</p>
</blockquote>
</aside>
<p>Yeah exactly. And I see no reason why you wouldn’t do better than Zod here. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>I pondered having my own wrapper that always also supplies the schema but I don’t know, felt somewhat clunky to me. Though it’s doable.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>I agree, I built the <a href="https://hexdocs.pm/zoi/Zoi.Schema.html" rel="noopener nofollow ugc">schema module</a> for this, you can traverse the schema and add metadata that should apply for all types.</p>
</blockquote>
</aside>
<p>I just had Claude verify this and it’s only partially true:</p>
<ul>
<li><code>Zoi.coerce</code> on a string / date / integer type does enable type coercion</li>
<li>But it does not set it on maps. So we still have to have it on every level.</li>
</ul>
<p>Thanks, I’ll use the partial fix but will have to keep having <code>coerce: true</code> on each map because I need nested parsing.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>I think this already works, I have tests for one argument refinements <a href="https://github.com/phcurado/zoi/blob/main/test/zoi_test.exs#L4277-L4277" rel="noopener nofollow ugc">here</a>.</p>
</blockquote>
</aside>
<p>Derp, sorry. I did not exhaustively verify this. Just did. Yep, it works fine.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>Good feedback thank you. I will analyze in more detail each topic and will see areas for improving.</p>
</blockquote>
</aside>
<p>Thank you back – Zoi is fantastic and I needed a similar library many times over the years.</p>
<aside class="quote no-group" data-username="phcurado" data-post="55" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>Overall if requires too many changes we can always build another library that integrates <code>zoi</code> and <code>ecto</code> that handles the edge cases since both libraries have their own architecture.</p>
</blockquote>
</aside>
<p>Yep, I am fully on board and will help you with that if needed. For most non-greenfield projects the reality is that compatibility with the current ecosystem and a gradual migration are how people integrate new good libraries.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386881" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/zoi-schema-validation-library-inspired-by-zod/72108/56">Post #55</a>
	                </div>
	            </div>
              <div id="likers-container-386881" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386881"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>