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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>If you mean with <code>validate_change(changeset, field, validator_function)</code> this also wouldn’t work because the validator is only invoked on changed fields.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="294319" 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/float-comparision-in-ecto/56987/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-294319" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294319"
                     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="294320" data-post-id="294320">
  <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>No, I mean our own function that accepts a changeset + args and returns a changeset. Here:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"> def lower_price_changeset(product, new_price) do
    old_price = product.unit_price
    product
    |&gt; change(unit_price: new_price)
    |&gt; validate_price(old_price)
  end

  def validate_price(%Changeset{} = changeset, old_price) do
    new_price = get_change(changeset, :unit_price)

    cond do
      new_price &gt; old_price -&gt;
        add_error(changeset, :unit_price, "is bigger than the old price", old_price: old_price)

      new_price == old_price -&gt;
        add_error(changeset, :unit_price, "is equal to the old price", old_price: old_price)

      true -&gt;
        changeset
    end
  end
</code></pre>
<p>An even better option would be to merge both <code>change(unit_price: new_price)</code> and the function above into something like <code>maybe_put_new_price</code>. The benefit being slightly more readable code + not having to pull out the new price via <code>get_change</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="294320" 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/float-comparision-in-ecto/56987/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-294320" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294320"
                     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="294337" data-post-id="294337">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="03juan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/03juan/120/23111_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  03juan
                  </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="11" data-topic="56987">
<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’d also advise for a custom validator function in this case. It’s no big deal and I don’t know why people are so averse to it; it’s just a pipe of functions as all others in Elixir. But I do get it, some get cold feet because previous frameworks gave them PTSD. Can relate!</p>
</blockquote>
</aside>
<p>Hard agree. But here we’re already presenting 4 different ways to do things, so I can see why some would be averse! The beauty of the functional approach does make it easier to swap things out and see what works best.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="294337" 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/float-comparision-in-ecto/56987/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-294337" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294337"
                     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="294457" data-post-id="294457">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/dimitarvp" rel="nofollow">@dimitarvp</a> Something just came to mind… <code>change</code> may be the wrong function for this use case if we want the most idiomatic way to error for a dynamic test of <code>new &lt; old</code> when new could be == old.</p>
<p>The docs also say about <code>change</code>:</p>
<blockquote>
<p>Note the <code>value</code> is directly stored in the changeset with no validation whatsoever. For this reason, <strong>this function is meant for working with data internal to the application.</strong></p>
</blockquote>
<blockquote>
<p>This function is useful for:</p>
<ul>
<li>wrapping a struct inside a changeset</li>
<li><strong>directly changing a struct without performing castings nor validations</strong></li>
<li>directly bulk-adding changes to a changeset</li>
</ul>
</blockquote>
<p>But as we’ve seen the issue is that the change is not added when the values are the same.</p>
<p>I haven’t gone through the “Programming Phoenix LiveView” book in detail but I assume this is an exercise? All their changeset examples use <code>cast</code> instead of <code>change</code> and this is the most idiomatic approach to solve this problem, with an extra option.</p>
<blockquote>
<ul>
<li><code>:force_changes</code> - a boolean indicating whether to include values that don’t alter the current data in <code>:changes</code>. Defaults to <code>false</code></li>
</ul>
</blockquote>
<p>The reason to use cast is that if this changeset will be called with params from a form, it will attempt to cast the string value from the client into float, and return a cast error if that fails.</p>
<p>In which case we’d want to pass the params as an attribute to <code>cast</code></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def lower_price_changeset(%Product{unit_price: old_price} = product, params) do
  product
  |&gt; cast(params, [:unit_price], force_changes: true)
  |&gt; validate_number(:unit_price, less_than: old_price)
end

iex&gt; Pento.Catalog.Product.lower_price_changeset(p, %{"unit_price" =&gt; "9.0"}) 
#Ecto.Changeset&lt;action: nil,
 changes: %{unit_price: 9.0},
 errors: [
   unit_price: {"must be less than %{number}",
     [validation: :number, kind: :less_than, number: 9.0]}
 ],
 data: #Pento.Catalog.Product&lt;&gt;,
 valid?: false&gt;
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="294457" data-batch-url="/posts/batch_likers">
                        2
                      </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/float-comparision-in-ecto/56987/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-294457" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294457"
                     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="294467" data-post-id="294467">
  <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>You made me realize that I have mistaken <code>force_change(...)</code> with <code>cast(..., force_changes: true)</code>. That’s why I was confused at the start of the thread that it’s not working.</p>
<p>Thank you!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="294467" 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/float-comparision-in-ecto/56987/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-294467" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294467"
                     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="294479" data-post-id="294479">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The many options for changeset functions have made them feel intractable in exactly this way.. ‘what’s the right way to tackle my edge case that’s not spelled out in the docs’.  Just wanted to post that I’m very glad I was corrected and that <a class="mention" href="/u/acke" rel="nofollow">@acke</a>’s original question was talked this far out as this has helped me.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="294479" 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/float-comparision-in-ecto/56987/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-294479" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294479"
                     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="294512" data-post-id="294512">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It certainly does make them feel that way, and I’m also glad that we can discuss such things in these forums. At least the dev team is always open to contributions to improve the docs so I may give this a shot unless someone else gets inspired. If so ping me and we can work on it together <img src="https://forum.elixirforum.com/images/emoji/apple/wink.png?v=15" title=":wink:" class="emoji" alt=":wink:" 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="294512" 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/float-comparision-in-ecto/56987/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-294512" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="294512"
                     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>