title: Elixir changeset custom validation
body: <p>I'm having a bit of trouble trying to implement a custom changeset validation.
  My schema is:</p>
  <pre><code>defenum(VersionStateEnum, [&quot;draft&quot;, &quot;active&quot;])
  schema &quot;versions&quot; do
    field :expires_at, :utc_datetime
    field :state, VersionStateEnum
  end
  </code></pre>
  <p>The validation I'm trying to implement is: The expires_at can only be set if the state is draft (this should also be valid for updates, I should not be able to remove the expires_at if the state is still draft)
  I tried the following:</p>
  <pre><code>defp validate_expires_at(changeset) do                                                                                                                                                                           
      expires_at = get_change(changeset, :expires_at)                                                                                                                                                                
      cond do                                                                                                                                                                                                        
        get_change(changeset, :state) == :draft -&gt;                                                                                                                                                                   
          case expires_at do                                                                                                                                                                                         
            nil -&gt; add_error(changeset, :expires_at, &quot;can't be blank when state is draft&quot;)                                                                                                                           
            _ -&gt; changeset                                                                                                                                                                                           
          end                                                                                                                                                                                                        
        get_change(changeset, :state) == :active -&gt;                                                                                                                                                                  
          case expires_at do                                                                                                                                                                                         
            nil -&gt; changeset                                                                                                                                                                                         
            _ -&gt; add_error(changeset, :expires_at, &quot;cannot be set when state is not draft&quot;)                                                                                                                          
          end                                                                                                                                                                                                        
        true -&gt;                                                                                                                                                                                                      
          changeset                                                                                                                                                                                                  
      end                                                                                                                                                                                                            
    end
  end
  </code></pre>
  <p>But it doesn't really work as I can update the expires_at to nil even if the state is draft. Any help is appreciated.</p>
  <p>Edit 1:
  My changeset:</p>
  <pre><code>@required_fields [                                                                                                                                                                                                                                                                                                                                                                                               
      :state                                                                                                                                                                                                                                                                                                                                                                                                         
    ]                                                                                                                                                                                                                
  @optional_fields [:expires_at]
  def changeset(model, params \\ nil) do                                                                                                                                                                           
    model                                                                                                                                                                                                          
    |&gt; cast(params, @required_fields ++ @optional_fields)                                                                                                                                                          
    |&gt; validate_required(@required_fields)                                                                                                                                                                         
    |&gt; validate_expires_at()                                                                                                                                                                                       
  end
  </code></pre>
  <p>Where it's being called:</p>
  <pre><code>def create_document(attrs \\ %{}) do                                                                                                                                                                             
    %Document{}                                                                                                                                                                                                    
    |&gt; Document.changeset(attrs)                                                                                                                                                                                   
    |&gt; Repo.insert()                                                                                                                                                                                               
  end
  </code></pre>