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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nathanl" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nathanl/120/39891_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nathanl
                    <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">
								<p><a class="mention" href="/u/michalmuskala" rel="nofollow">@michalmuskala</a></p>
<p>If I understand you correctly, what you’re describing is:</p>
<ol>
<li>User fills the form</li>
<li>Frontend makes an AJAX request specifically to check for uniqueness, and may set an error accordingly</li>
<li>When frontend says the form is valid, it sends the data to the backend,</li>
<li>Backend does not bother checking uniqueness in the validation step because that’s already been done, but does react as usual if there’s a constraint violation</li>
</ol>
<p>That makes sense to me. It’s the same principle, carried further; the user typically can correct a uniqueness issue even before submitting the form.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="23922" 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/a-case-for-validating-uniqueness/3637/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-23922" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="23922"
                     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="23972" data-post-id="23972">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="nathanl" data-post="1" data-topic="3637">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nathanl/48/39891_2.png" class="avatar"> nathanl:</div>
<blockquote>
<p>The downsides of doing this are that 1) your validation phase now requires the database, which makes testing a little worse 2) it’s not very DRY 3) it’s extra work. But 1) can be dealt with by breaking having a run_database_dependent_validations function and testing it separately. 2) and 3) are developer pain that I think is justified by the better user experience.</p>
</blockquote>
</aside>
<p>This sums it up really well. I would add:</p>
<ol>
<li>
<p>“Making testing a little worse” may no longer be a downside on Phoenix v1.3. With the new generators we are getting rid of the pure/impure separation in controllers due to the new contexts and the fact we can now run tests that talk to the database concurrently. You will still want to write pure code, especially in views, but it is not a separation we will be pushing between controllers and models (which won’t even exist).</p>
</li>
<li>
<p>However, adding <code>validate_unique</code> makes it very hard to push people towards the proper direction.  It is very easy to fallback to “bad habits” if they are made easily accessible. We saw that happening with callbacks. I can see people trying out <code>validate_unique</code> out of muscle memory alone. If we are going to add such, I would rather call it <code>unsafe_validate_unique</code> or something that makes it less reachable and more explicit.</p>
</li>
</ol> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="23972" data-batch-url="/posts/batch_likers">
                        3
                      </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/a-case-for-validating-uniqueness/3637/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-23972" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="23972"
                     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="23978" data-post-id="23978">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sasajuric" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/120/991_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sasajuric
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Elixir In Action</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>This is precisely how we did it in my previous company. On a change event we’d issue an ajax to validate the user name. For other inputs, we’d validate them directly on the client. For the vast majority of cases this would ensure that if the submit button is enabled, the request would succeed. Of course, you still need to verify correctness on the server side, but now you don’t need to pollute DB with the validation 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="23978" 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/a-case-for-validating-uniqueness/3637/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-23978" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="23978"
                     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="24508" data-post-id="24508">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nathanl" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nathanl/120/39891_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nathanl
                    <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 group-livebook_core_team" data-username="josevalim" data-post="13" data-topic="3637">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/48/1787_2.png" class="avatar"> josevalim:</div>
<blockquote>
<p>If we are going to add such, I would rather call it unsafe_validate_unique or something that makes it less reachable and more explicit.</p>
</blockquote>
</aside>
<p>I agree. I’ll try implementing this and get back to 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="24508" 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/a-case-for-validating-uniqueness/3637/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-24508" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="24508"
                     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="24519" data-post-id="24519">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="steve" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  steve
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve found myself implementing a similar function for forms that require multiple constraints, especially when a database transaction is needed to insert data across more than one table. The requirements were that the forms need to work without JavaScript, so using AJAX wasn’t an option. I’d like to share my experiences with it.</p>
<p>For  a practical example, let’s take a look at the use case in <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a>’s <a href="http://blog.plataformatec.com.br/2016/05/ectos-insert_all-and-schemaless-queries" rel="noopener nofollow ugc">schemaless query blog post</a> under the <em>Schemas are Mappers</em> section. We have a <code>Registration</code> form that splits data between a <code>Profile</code> and an <code>Account</code>. Let’s say that the profile schema also has a username that needs to be unique. If the email and the username turned out to be taken already, it would be nice to show the user both errors at once instead of making them submit the form twice.</p>
<p>I’m making the following function up off the top of my head, so please excuse any errors or inefficiency in it, but the idea for a function that validates uniqueness would be along the lines of the following:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defp validate_unique_email(%Ecto.Changeset{} = changeset, options \\ [])
    when is_list(options) do
  if changeset.errors[:email] do
    changeset
  else
    if is_email_unique?(changeset.changes.email) do
      changeset
    else
      put_unique_validation_error(changeset, :email, options)
    end
  end
end
</code></pre>
<p>Keep in mind, the changeset has already been validated before entering this function; it is local to the registration module. If there is already an existing error on the <code>email</code> field, the database call is bypassed. If there is no pre-existing error, the <code>is_email_unique?</code> function hits the database returns a boolean about whether or not the email already exists. If the email is unique, the changeset is simply passed along. If the email already exists, the utility function <code>put_unique_validation_error</code> adds the validation error to the changeset (passing along the options, such as <code>options[:message]</code>). The username would go through a similar process.</p>
<p>Since there are a couple times uniqueness is validated, the <code>put_unique_constraint_error</code> function is generalized to allow developers to easily add unique constraint violations to the changeset. (Speaking of, there is no error information added to unique constraints in Ecto outside of the messages at the moment. For example, a length validation error adds <code>[validation: :length]</code> to the error. It might be a good idea to add something like <code>[constraint: :unique]</code> or <code>[constraint: :foreign_key]</code> for when the constraints fail.)</p>
<p>After that, when the data is actually inserted into the database, both fields still have the <code>unique_constraint</code> placed on both of them before being inserted. This prevents any sort of race from happening.</p>
<p>This is a rare use case, but one I found myself needing. It would be nice to have it built into Ecto, but I agree that it should stay outside of Changeset. If there’s only a single constraint, the normal constraints more than suffice.</p>
<p>Edit: I do want to say that adding this functionality to my application was trivial. There were only two separate cases where it was needed, and the context was bound within the module responsible for that particular form. Because of that, it was very clear that this check was hitting the database to do the validation. The ease of implementation and clarity of action could be used to argue that the functionality doesn’t really need to be added since it’s such an edge case. If it were to be added, I see Jose’s recommendation of adding it as something called <code>unsafe_validate_unique</code> as a good middle ground.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="24519" 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/a-case-for-validating-uniqueness/3637/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-24519" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="24519"
                     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="24697" data-post-id="24697">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The general version of the problem you describe has been discussed at length in the DDD community under the rubric of “cross aggregate rule validation”. A number of solutions have been suggested. You might get some ideas looking in to those discussions.</p>
<p>Here is a good place to start that discusses aggregate design and rule validations: <a href="http://dddcommunity.flywheelsites.com/library/vernon_2011/" rel="noopener nofollow ugc">http://dddcommunity.flywheelsites.com/library/vernon_2011/</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="24697" data-batch-url="/posts/batch_likers">
                        4
                      </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/a-case-for-validating-uniqueness/3637/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-24697" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="24697"
                     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="107610" data-post-id="107610">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="nathanl" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nathanl/120/39891_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  nathanl
                    <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">
								<p>FWIW, this discussion eventually led to the creation of <a href="https://hexdocs.pm/ecto/Ecto.Changeset.html#unsafe_validate_unique/4" class="inline-onebox" rel="noopener nofollow ugc">Ecto.Changeset — Ecto v3.14.0</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="107610" data-batch-url="/posts/batch_likers">
                        3
                      </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/a-case-for-validating-uniqueness/3637/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-107610" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107610"
                     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>