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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dfalling" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dfalling
                    <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="sodapopcan" data-post="11" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p><code>field :subject, :string, default: ""</code></p>
</blockquote>
</aside>
<p>My understanding is this default only applies to new structs, it doesn’t do anything for change casts.</p>
<p>To prevent writing <code>nil</code> to the db I think you need to make a custom validator as well:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  defp validate_not_null(changeset, fields) do
    dbg(changeset)

    Enum.reduce(fields, changeset, fn field, changeset -&gt;
      case {changed?(changeset, field), get_change(changeset, field)} do
        {true, nil} -&gt; add_error(changeset, field, "can't be null")
        _ -&gt; changeset
      end
    end)
  end
</code></pre>
<p>And then hopefully overriding the <code>empty_values</code> to not include <code>""</code> will keep the Changeset from transforming empty string’s to nil.</p>
<p>But it’s quite a bit of fighting against Ecto’s standard behavior.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319970" 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/how-do-you-model-your-nullable-strings/62057/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-319970" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319970"
                     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 #11"></div>
  </section>
</div>
    <div class="postbit" id="319973" data-post-id="319973">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dfalling" data-post="6" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/48.png" class="avatar"> dfalling:</div>
<blockquote>
<p><code>validate_change</code> will not run for <code>nil</code> values.</p>
</blockquote>
</aside>
<p>This is not correct. <code>validate_change</code> only runs on changes, which means if you set a column, which is <code>nil</code> to <code>nil</code> (without forcing it) is not considered a change. If you default a column to <code>""</code> and set it to <code>nil</code> it will be considered a change.</p>
<p>So this might just be it:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">import Ecto.Changeset

{%{subject: ""}, %{subject: :string}}
|&gt; cast(params, [:subject], empty_values: [nil])
|&gt; validate_change(:subject, :required, fn 
  field, nil -&gt; [{field, "can't be empty"}]
  _, _ -&gt; []
end)
</code></pre>
<p><code>validate_required</code> is indeed a bit of an odd ball in the set of validations, because it’s the only validation, which doesn’t just look at changes, but also at the existing value in the base data of a changeset.</p>
<aside class="quote no-group" data-username="joey_the_snake" data-post="4" data-topic="62057" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/j/c37758/48.png" class="avatar"> joey_the_snake:</div>
<blockquote>
<p>I’ve seen more than one person thrown off by this as well. So the idea that Ecto <strong>needs</strong> to behave this way is a bit strong. It is a design choice to behave in this manner because many of it users find it to be a good default. But that does throw off/confuse other users.</p>
</blockquote>
</aside>
<p>I mean sure you can call it a design decision, but “casting” in ecto is explicitly the act of converting weakly typed representations of a value into the corresponding elixir runtime value (see <code>Ecto.Type.cast/1</code>). That means there will be some tradeoffs to be made and not every external input you have provides the same level of information. Ecto does cater to a common type of input, which provides the least amount of information – form data, where all you got is strings (or the lack of in some situations).</p>
<p>If you already have proper types you’re can skip that by using <code>Ecto.Changeset.change</code> or <code>Ecto.Changeset.put_change</code> and casting will be skipped.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319973" 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/how-do-you-model-your-nullable-strings/62057/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-319973" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319973"
                     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 #12"></div>
  </section>
</div>
    <div class="postbit" id="319976" data-post-id="319976">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dfalling" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dfalling
                    <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="LostKobrakai" data-post="13" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<pre data-code-wrap="elixir"><code class="lang-elixir">{%{subject: ""}, %{subject: :string}}
|&gt; cast(params, [:subject], empty_values: [nil])
|&gt; validate_change(:subject, :required, fn 
  field, nil -&gt; [{field, "can't be empty"}]
  _, _ -&gt; []
end)
</code></pre>
</blockquote>
</aside>
<p>Oof, I’m so confused now- so if I use <code>empty_values: [nil]</code>, then after casting a <code>%{subject: nil</code>}, I’ll have <code>changes: %{subject: ""}</code> Then the <code>validate_change</code> will be called with an empty string (so I actually don’t need it anymore, it looks like <code>nil</code> can’t make it through the cast).</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  defp validate_not_null(changeset, fields) do
    Enum.reduce(fields, changeset, fn field, changeset -&gt;
      validate_change(changeset, field, fn
        field, nil -&gt; [{field, "can't be empty"}]
        _, _ -&gt; []
      end)
    end)
  end
</code></pre>
<p>Without adding <code>empty_values: [nil]</code>, my changes are <code>%{subject: nil}</code>, and my validateChange is never called. I <em>think</em> that’s expected behaviour: <a href="https://forum.elixirforum.com/t/ecto-changeset-validate-change-and-setting-fields-to-nil/33204/3" class="inline-onebox" rel="nofollow">`Ecto.Changeset.validate_change` and setting fields to `nil` - #3 by josevalim</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319976" 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/how-do-you-model-your-nullable-strings/62057/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-319976" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319976"
                     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 #13"></div>
  </section>
</div>
    <div class="postbit" id="319977" data-post-id="319977">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dfalling" data-post="14" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/48.png" class="avatar"> dfalling:</div>
<blockquote>
<p>Oof, I’m so confused now- so if I use <code>empty_values: [nil]</code>, then after casting a <code>%{subject: nil</code>}, I’ll have <code>changes: %{subject: ""}</code></p>
</blockquote>
</aside>
<p>Then I’d suggest updating ecto. Because on my end I get <code>changes: %{subject: nil}</code> with <code>%{"subject" =&gt; nil}</code> as input.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319977" 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/how-do-you-model-your-nullable-strings/62057/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-319977" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319977"
                     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 #14"></div>
  </section>
</div>
    <div class="postbit" id="319978" data-post-id="319978">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dfalling" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dfalling
                    <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="LostKobrakai" data-post="15" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>Then I’d suggest updating ecto. Because on my end I get <code>changes: %{subject: nil}</code> with <code>%{"subject" =&gt; nil}</code> as input.</p>
</blockquote>
</aside>
<aside class="quote no-group" data-username="sodapopcan" data-post="11" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p><code>field :subject, :string, default: ""</code></p>
</blockquote>
</aside>
<p>I was wrong- with the <code>empty_values</code> set to <code>[nil]</code>, Ecto does actually fallback to using the schema’s default value. So <code>empty_values</code> + <code>default</code> does exactly what I was looking for, without needing any custom validators.</p>
<p>Thanks everyone!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319978" 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/how-do-you-model-your-nullable-strings/62057/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-319978" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319978"
                     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 #15"></div>
  </section>
</div>
    <div class="postbit" id="319981" data-post-id="319981">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dfalling" data-post="12" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/48.png" class="avatar"> dfalling:</div>
<blockquote>
<p>My understanding is this default only applies to new structs, it doesn’t do anything for change casts.</p>
</blockquote>
</aside>
<p>Perhaps you have some code that is causing this to be the case?  You made me question myself so I set a random nullable string field to <code>default: ""</code> in a project, saved an existing record where it was already <code>NULL</code> and it got updated to <code>""</code>.  Then I removed the default, saved it again and it got set back to <code>NULL</code>.</p>
<p>In any event, glad you found a solution!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="319981" 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/how-do-you-model-your-nullable-strings/62057/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-319981" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="319981"
                     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 #16"></div>
  </section>
</div>
    <div class="postbit" id="320049" data-post-id="320049">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dfalling" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dfalling
                    <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="sodapopcan" data-post="17" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p>Perhaps you have some code that is causing this to be the case? You made me question myself so I set a random nullable string field to <code>default: ""</code> in a project, saved an existing record where it was already <code>NULL</code> and it got updated to <code>""</code>. Then I removed the default, saved it again and it got set back to <code>NULL</code>.</p>
</blockquote>
</aside>
<p>Yep, I was wrong about this. Sorry this was a flurry of comments as I kept trying different things out.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="320049" 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/how-do-you-model-your-nullable-strings/62057/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-320049" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="320049"
                     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 #17"></div>
  </section>
</div>
    <div class="postbit" id="320138" data-post-id="320138">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="dfalling" data-post="18" data-topic="62057">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/d/e5b9ba/48.png" class="avatar"> dfalling:</div>
<blockquote>
<p>flurry of comments</p>
</blockquote>
</aside>
<p>Again, apologies for misreading your example!  My first messages were written under the misconception that you were advocating for defaulting an email address to <code>""</code> and I was a little concerned <img src="https://forum.elixirforum.com/images/emoji/apple/sweat_smile.png?v=15" title=":sweat_smile:" class="emoji" alt=":sweat_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="320138" 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/how-do-you-model-your-nullable-strings/62057/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-320138" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="320138"
                     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>