title: Trailblazer Contracts overrides params
body: <p>I have this operation:</p>
  
  
  
  <pre><code>require 'bcrypt'
  
  class User::Create &lt; Trailblazer::Operation
  
    extend Contract::DSL
  
    contract 'params', (Dry::Validation.Schema do
      required(:email).filled
      required(:password).filled
    end)
  
    step      Contract::Validate(name: 'params'), before: 'operation.new'
    step      Model(User, :new)
    success   :generate_token
    success   :encrypt_password
    success   :assign_user_values
    step      Contract::Build(constant: User::Contract::Create)
    step      Contract::Validate()
    step      Contract::Persist()
  
    def generate_token(options, *)
      token = loop do
        random_token = SecureRandom.uuid
        break random_token unless User.exists?(token: random_token)
      end
  
      options['data.token'] = token
    end
  
    def encrypt_password(options, params:, **)
      options['data.password'] = BCrypt::Password.create(params[:password])
    end
  
    def assign_user_values(options, params:, **)
      options['model'].token = options['data.token']
      options['model'].password = options['data.password']
      options['model'].role = 'user'
    end
  
  end
  </code></pre>
  
  <p>When I run the operation, I get this output:</p>
  
  <pre><code>User::Create.(email: 'bidule@gmail.com', password: 'bidule')
    User Exists (0.6ms)  SELECT  1 AS one FROM "users" WHERE "users"."token" = $1 LIMIT $2  [["token", "64423af4-5741-46af-9756-15715a632d75"], ["LIMIT", 1]]
     (0.6ms)  SELECT COUNT(*) FROM "users" WHERE "users"."email" = $1  [["email", "bidule@gmail.com"]]
     (0.4ms)  SELECT COUNT(*) FROM "users" WHERE "users"."token" = $1  [["token", "64423af4-5741-46af-9756-15715a632d75"]]
     (0.3ms)  BEGIN
    SQL (0.5ms)  INSERT INTO "users" ("email", "password", "role", "token", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["email", "bidule@gmail.com"], ["password", "bidule"], ["role", "user"], ["token", "64423af4-5741-46af-9756-15715a632d75"], ["created_at", "2017-12-30 23:34:24.456817"], ["updated_at", "2017-12-30 23:34:24.456817"]]
     (2.8ms)  COMMIT
  =&gt; &lt;Result:true &lt;Skill {"contract.params.params"=&gt;{:email=&gt;"bidule@gmail.com", :password=&gt;"bidule"}, "representer.params.class"=&gt;false, "result.contract.params"=&gt;#&lt;Dry::Validation::Result output={:email=&gt;"bidule@gmail.com", :password=&gt;"bidule"} errors={}&gt;, "model.class"=&gt;User(id: integer, email: string, password: string, role: string, token: string, created_at: datetime, updated_at: datetime), "model.action"=&gt;:new, "model"=&gt;#&lt;User id: 17, email: "bidule@gmail.com", password: "bidule", role: "user", token: "64423af4-5741-46af-9756-15715a632d75", created_at: "2017-12-30 23:34:24", updated_at: "2017-12-30 23:34:24"&gt;, "result.model"=&gt;&lt;Result:true {} &gt;, "data.token"=&gt;"64423af4-5741-46af-9756-15715a632d75", "data.password"=&gt;"$2a$10$gy19txopkeM5Vovx4/ohvOuZAP2CMwtBTcCwswJq9Ije7NVrKj8Ce", "contract.default"=&gt;#&lt;User::Contract::Create:0x0000000004e316e8 @fields={"email"=&gt;"bidule@gmail.com", "password"=&gt;"bidule", "role"=&gt;"user", "token"=&gt;"64423af4-5741-46af-9756-15715a632d75"}, @model=#&lt;User id: 17, email: "bidule@gmail.com", password: "bidule", role: "user", token: "64423af4-5741-46af-9756-15715a632d75", created_at: "2017-12-30 23:34:24", updated_at: "2017-12-30 23:34:24"&gt;, @mapper=#&lt;#&lt;Class:0x0000000004e31558&gt;:0x0000000004e30bf8 @model=#&lt;User id: 17, email: "bidule@gmail.com", password: "bidule", role: "user", token: "64423af4-5741-46af-9756-15715a632d75", created_at: "2017-12-30 23:34:24", updated_at: "2017-12-30 23:34:24"&gt;&gt;, @_changes={"email"=&gt;true, "password"=&gt;true}, @errors=#&lt;Reform::Form::ActiveModel::Errors:0x0000000004e30338 @base=#&lt;User::Contract::Create:0x0000000004e316e8 ...&gt;, @messages={}, @details={}&gt;&gt;, "contract.default.params"=&gt;{:email=&gt;"bidule@gmail.com", :password=&gt;"bidule"}, "representer.default.class"=&gt;false, "result.contract.default"=&gt;#&lt;User::Contract::Create:0x0000000004e316e8 @fields={"email"=&gt;"bidule@gmail.com", "password"=&gt;"bidule", "role"=&gt;"user", "token"=&gt;"64423af4-5741-46af-9756-15715a632d75"}, @model=#&lt;User id: 17, email: "bidule@gmail.com", password: "bidule", role: "user", token: "64423af4-5741-46af-9756-15715a632d75", created_at: "2017-12-30 23:34:24", updated_at: "2017-12-30 23:34:24"&gt;, @mapper=#&lt;#&lt;Class:0x0000000004e31558&gt;:0x0000000004e30bf8 @model=#&lt;User id: 17, email: "bidule@gmail.com", password: "bidule", role: "user", token: "64423af4-5741-46af-9756-15715a632d75", created_at: "2017-12-30 23:34:24", updated_at: "2017-12-30 23:34:24"&gt;&gt;, @_changes={"email"=&gt;true, "password"=&gt;true}, @errors=#&lt;Reform::Form::ActiveModel::Errors:0x0000000004e30338 @base=#&lt;User::Contract::Create:0x0000000004e316e8 ...&gt;, @messages={}, @details={}&gt;&gt;} {"params"=&gt;{:email=&gt;"bidule@gmail.com", :password=&gt;"bidule"}} {"pipetree"=&gt;[&gt;contract.params.validate,&gt;operation.new,&gt;model.build,&gt;generate_token,&gt;encrypt_password,&gt;assign_user_values,&gt;contract.build,&gt;contract.default.validate,&gt;persist.save], "contract.params"=&gt;#&lt;#&lt;Class:0x0000000005261790&gt;:0x0000000005245798 @type_map={}, @config=#&lt;#&lt;Class:0x0000000004b1a518&gt;:0x00000000052616a0 @config={:input_processor=&gt;:noop, :hash_type=&gt;:weak, :type_map=&gt;{}, :path=&gt;[], :predicates=&gt;Dry::Logic::Predicates, :registry=&gt;#&lt;Dry::Validation::PredicateRegistry::Unbound:0x0000000005261588 @external=Dry::Logic::Predicates, @predicates={}&gt;, :messages=&gt;:yaml, :messages_file=&gt;nil, :namespace=&gt;nil, :rules=&gt;[[:rule, [:email, [:and, [[:rule, [:email, [:predicate, [:key?, [[:name, :email], [:input, Undefined]]]]]], [:rule, [:email, [:key, [:email, [:predicate, [:filled?, [[:input, Undefined]]]]]]]]]]]], [:rule, [:password, [:and, [[:rule, [:password, [:predicate, [:key?, [[:name, :password], [:input, Undefined]]]]]], [:rule, [:password, [:key, [:password, [:predicate, [:filled?, [[:input, Undefined]]]]]]]]]]]]], :checks=&gt;[], :options=&gt;{}, :input=&gt;nil, :input_rule=&gt;nil, :dsl_extensions=&gt;nil, :input_processor_map=&gt;{:sanitizer=&gt;#&lt;Dry::Validation::InputProcessorCompiler::Sanitizer:0x0000000004afb618 @type_compiler=#&lt;Dry::Types::Compiler:0x0000000004afb5f0 @registry=Dry::Types&gt;&gt;, :json=&gt;#&lt;Dry::Validation::InputProcessorCompiler::JSON:0x0000000004afb5c8 @type_compiler=#&lt;Dry::Types::Compiler:0x0000000004afb5a0 @registry=Dry::Types&gt;&gt;, :form=&gt;#&lt;Dry::Validation::InputProcessorCompiler::Form:0x0000000004afb578 @type_compiler=#&lt;Dry::Types::Compiler:0x0000000004afb550 @registry=Dry::Types&gt;&gt;}, :type_specs=&gt;false}&gt;, @predicates=#&lt;Dry::Validation::PredicateRegistry::Bound:0x0000000005245720 @external=Dry::Logic::Predicates, @predicates={}, @schema=#&lt;#&lt;Class:0x0000000005261790&gt;:0x0000000005245798 ...&gt;&gt;, @rule_compiler=#&lt;Dry::Validation::SchemaCompiler:0x0000000005245630 @predicates=#&lt;Dry::Validation::PredicateRegistry::Bound:0x0000000005245720 @external=Dry::Logic::Predicates, @predicates={}, @schema=#&lt;#&lt;Class:0x0000000005261790&gt;:0x0000000005245798 ...&gt;&gt;, @options={:predicate_registry=&gt;#&lt;Dry::Validation::PredicateRegistry::Unbound:0x0000000005261588 @external=Dry::Logic::Predicates, @predicates={}&gt;, :message_compiler=&gt;#&lt;Dry::Validation::MessageCompiler:0x00000000052459c8 @messages=#&lt;Dry::Validation::Messages::YAML data={"en.errors.or"=&gt;"or", "en.errors.array?"=&gt;"must be an array", "en.errors.empty?"=&gt;"must be empty", "en.errors.excludes?"=&gt;"must not include %{value}", "en.errors.excluded_from?.arg.default"=&gt;"must not be one of: %{list}", "en.errors.excluded_from?.arg.range"=&gt;"must not be one of: %{list_left} - %{list_right}", "en.errors.exclusion?"=&gt;"must not be one of: %{list}", "en.errors.eql?"=&gt;"must be equal to %{left}", "en.errors.not_eql?"=&gt;"must not be equal to %{left}", "en.errors.filled?"=&gt;"must be filled", "en.errors.format?"=&gt;"is in invalid format", "en.errors.number?"=&gt;"must be a number", "en.errors.odd?"=&gt;"must be odd", "en.errors.even?"=&gt;"must be even", "en.errors.gt?"=&gt;"must be greater than %{num}", "en.errors.gteq?"=&gt;"must be greater than or equal to %{num}", "en.errors.hash?"=&gt;"must be a hash", "en.errors.included_in?.arg.default"=&gt;"must be one of: %{list}", "en.errors.included_in?.arg.range"=&gt;"must be one of: %{list_left} - %{list_right}", "en.errors.inclusion?"=&gt;"must be one of: %{list}", "en.errors.includes?"=&gt;"must include %{value}", "en.errors.bool?"=&gt;"must be boolean", "en.errors.true?"=&gt;"must be true", "en.errors.false?"=&gt;"must be false", "en.errors.int?"=&gt;"must be an integer", "en.errors.float?"=&gt;"must be a float", "en.errors.decimal?"=&gt;"must be a decimal", "en.errors.date?"=&gt;"must be a date", "en.errors.date_time?"=&gt;"must be a date time", "en.errors.time?"=&gt;"must be a time", "en.errors.key?"=&gt;"is missing", "en.errors.attr?"=&gt;"is missing", "en.errors.lt?"=&gt;"must be less than %{num}", "en.errors.lteq?"=&gt;"must be less than or equal to %{num}", "en.errors.max_size?"=&gt;"size cannot be greater than %{num}", "en.errors.min_size?"=&gt;"size cannot be less than %{num}", "en.errors.none?"=&gt;"cannot be defined", "en.errors.str?"=&gt;"must be a string", "en.errors.type?"=&gt;"must be %{type}", "en.errors.size?.arg.default"=&gt;"size must be %{size}", "en.errors.size?.arg.range"=&gt;"size must be within %{size_left} - %{size_right}", "en.errors.size?.value.string.arg.default"=&gt;"length must be %{size}", "en.errors.size?.value.string.arg.range"=&gt;"length must be within %{size_left} - %{size_right}"}&gt;, @options={}, @full=false, @hints=true, @locale=:en, @default_lookup_options={:locale=&gt;:en}&gt;, :input_processor=&gt;#&lt;Proc:0x000000000385d1a0@/app/vendor/bundle/ruby/2.3.0/gems/dry-validation-0.11.1/lib/dry/validation/schema/class_interface.rb:11 (lambda)&gt;, :checks=&gt;[]}, @schema=#&lt;#&lt;Class:0x0000000005261790&gt;:0x0000000005245798 ...&gt;&gt;, @message_compiler=#&lt;Dry::Validation::MessageCompiler:0x00000000052459c8 @messages=#&lt;Dry::Validation::Messages::YAML data={"en.errors.or"=&gt;"or", "en.errors.array?"=&gt;"must be an array", "en.errors.empty?"=&gt;"must be empty", "en.errors.excludes?"=&gt;"must not include %{value}", "en.errors.excluded_from?.arg.default"=&gt;"must not be one of: %{list}", "en.errors.excluded_from?.arg.range"=&gt;"must not be one of: %{list_left} - %{list_right}", "en.errors.exclusion?"=&gt;"must not be one of: %{list}", "en.errors.eql?"=&gt;"must be equal to %{left}", "en.errors.not_eql?"=&gt;"must not be equal to %{left}", "en.errors.filled?"=&gt;"must be filled", "en.errors.format?"=&gt;"is in invalid format", "en.errors.number?"=&gt;"must be a number", "en.errors.odd?"=&gt;"must be odd", "en.errors.even?"=&gt;"must be even", "en.errors.gt?"=&gt;"must be greater than %{num}", "en.errors.gteq?"=&gt;"must be greater than or equal to %{num}", "en.errors.hash?"=&gt;"must be a hash", "en.errors.included_in?.arg.default"=&gt;"must be one of: %{list}", "en.errors.included_in?.arg.range"=&gt;"must be one of: %{list_left} - %{list_right}", "en.errors.inclusion?"=&gt;"must be one of: %{list}", "en.errors.includes?"=&gt;"must include %{value}", "en.errors.bool?"=&gt;"must be boolean", "en.errors.true?"=&gt;"must be true", "en.errors.false?"=&gt;"must be false", "en.errors.int?"=&gt;"must be an integer", "en.errors.float?"=&gt;"must be a float", "en.errors.decimal?"=&gt;"must be a decimal", "en.errors.date?"=&gt;"must be a date", "en.errors.date_time?"=&gt;"must be a date time", "en.errors.time?"=&gt;"must be a time", "en.errors.key?"=&gt;"is missing", "en.errors.attr?"=&gt;"is missing", "en.errors.lt?"=&gt;"must be less than %{num}", "en.errors.lteq?"=&gt;"must be less than or equal to %{num}", "en.errors.max_size?"=&gt;"size cannot be greater than %{num}", "en.errors.min_size?"=&gt;"size cannot be less than %{num}", "en.errors.none?"=&gt;"cannot be defined", "en.errors.str?"=&gt;"must be a string", "en.errors.type?"=&gt;"must be %{type}", "en.errors.size?.arg.default"=&gt;"size must be %{size}", "en.errors.size?.arg.range"=&gt;"size must be within %{size_left} - %{size_right}", "en.errors.size?.value.string.arg.default"=&gt;"length must be %{size}", "en.errors.size?.value.string.arg.range"=&gt;"length must be within %{size_left} - %{size_right}"}&gt;, @options={}, @full=false, @hints=true, @locale=:en, @default_lookup_options={:locale=&gt;:en}&gt;, @input_processor=#&lt;Proc:0x000000000385d1a0@/app/vendor/bundle/ruby/2.3.0/gems/dry-validation-0.11.1/lib/dry/validation/schema/class_interface.rb:11 (lambda)&gt;, @options={:predicate_registry=&gt;#&lt;Dry::Validation::PredicateRegistry::Unbound:0x0000000005261588 @external=Dry::Logic::Predicates, @predicates={}&gt;, :message_compiler=&gt;#&lt;Dry::Validation::MessageCompiler:0x00000000052459c8 @messages=#&lt;Dry::Validation::Messages::YAML data={"en.errors.or"=&gt;"or", "en.errors.array?"=&gt;"must be an array", "en.errors.empty?"=&gt;"must be empty", "en.errors.excludes?"=&gt;"must not include %{value}", "en.errors.excluded_from?.arg.default"=&gt;"must not be one of: %{list}", "en.errors.excluded_from?.arg.range"=&gt;"must not be one of: %{list_left} - %{list_right}", "en.errors.exclusion?"=&gt;"must not be one of: %{list}", "en.errors.eql?"=&gt;"must be equal to %{left}", "en.errors.not_eql?"=&gt;"must not be equal to %{left}", "en.errors.filled?"=&gt;"must be filled", "en.errors.format?"=&gt;"is in invalid format", "en.errors.number?"=&gt;"must be a number", "en.errors.odd?"=&gt;"must be odd", "en.errors.even?"=&gt;"must be even", "en.errors.gt?"=&gt;"must be greater than %{num}", "en.errors.gteq?"=&gt;"must be greater than or equal to %{num}", "en.errors.hash?"=&gt;"must be a hash", "en.errors.included_in?.arg.default"=&gt;"must be one of: %{list}", "en.errors.included_in?.arg.range"=&gt;"must be one of: %{list_left} - %{list_right}", "en.errors.inclusion?"=&gt;"must be one of: %{list}", "en.errors.includes?"=&gt;"must include %{value}", "en.errors.bool?"=&gt;"must be boolean", "en.errors.true?"=&gt;"must be true", "en.errors.false?"=&gt;"must be false", "en.errors.int?"=&gt;"must be an integer", "en.errors.float?"=&gt;"must be a float", "en.errors.decimal?"=&gt;"must be a decimal", "en.errors.date?"=&gt;"must be a date", "en.errors.date_time?"=&gt;"must be a date time", "en.errors.time?"=&gt;"must be a time", "en.errors.key?"=&gt;"is missing", "en.errors.attr?"=&gt;"is missing", "en.errors.lt?"=&gt;"must be less than %{num}", "en.errors.lteq?"=&gt;"must be less than or equal to %{num}", "en.errors.max_size?"=&gt;"size cannot be greater than %{num}", "en.errors.min_size?"=&gt;"size cannot be less than %{num}", "en.errors.none?"=&gt;"cannot be defined", "en.errors.str?"=&gt;"must be a string", "en.errors.type?"=&gt;"must be %{type}", "en.errors.size?.arg.default"=&gt;"size must be %{size}", "en.errors.size?.arg.range"=&gt;"size must be within %{size_left} - %{size_right}", "en.errors.size?.value.string.arg.default"=&gt;"length must be %{size}", "en.errors.size?.value.string.arg.range"=&gt;"length must be within %{size_left} - %{size_right}"}&gt;, @options={}, @full=false, @hints=true, @locale=:en, @default_lookup_options={:locale=&gt;:en}&gt;, :input_processor=&gt;#&lt;Proc:0x000000000385d1a0@/app/vendor/bundle/ruby/2.3.0/gems/dry-validation-0.11.1/lib/dry/validation/schema/class_interface.rb:11 (lambda)&gt;, :checks=&gt;[]}, @rules={:email=&gt;#&lt;Dry::Logic::Operations::And rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#key?&gt; options={:args=&gt;[:email], :id=&gt;:email}&gt;, #&lt;Dry::Logic::Operations::Key rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#filled?&gt; options={:args=&gt;[]}&gt;] options={:name=&gt;:email, :evaluator=&gt;#&lt;Dry::Logic::Evaluator::Key path=[:email]&gt;, :path=&gt;:email, :id=&gt;:email}&gt;] options={:id=&gt;:email}&gt;, :password=&gt;#&lt;Dry::Logic::Operations::And rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#key?&gt; options={:args=&gt;[:password], :id=&gt;:password}&gt;, #&lt;Dry::Logic::Operations::Key rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#filled?&gt; options={:args=&gt;[]}&gt;] options={:name=&gt;:password, :evaluator=&gt;#&lt;Dry::Logic::Evaluator::Key path=[:password]&gt;, :path=&gt;:password, :id=&gt;:password}&gt;] options={:id=&gt;:password}&gt;}, @checks={}, @executor=#&lt;Dry::Validation::Executor:0x000000000524f8b0 @steps=[#&lt;Dry::Validation::ProcessInput:0x000000000524f860 @processor=#&lt;Proc:0x000000000385d1a0@/app/vendor/bundle/ruby/2.3.0/gems/dry-validation-0.11.1/lib/dry/validation/schema/class_interface.rb:11 (lambda)&gt;&gt;, #&lt;Dry::Validation::ApplyRules:0x000000000524f838 @rules={:email=&gt;#&lt;Dry::Logic::Operations::And rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#key?&gt; options={:args=&gt;[:email], :id=&gt;:email}&gt;, #&lt;Dry::Logic::Operations::Key rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#filled?&gt; options={:args=&gt;[]}&gt;] options={:name=&gt;:email, :evaluator=&gt;#&lt;Dry::Logic::Evaluator::Key path=[:email]&gt;, :path=&gt;:email, :id=&gt;:email}&gt;] options={:id=&gt;:email}&gt;, :password=&gt;#&lt;Dry::Logic::Operations::And rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#key?&gt; options={:args=&gt;[:password], :id=&gt;:password}&gt;, #&lt;Dry::Logic::Operations::Key rules=[#&lt;Dry::Logic::Rule::Predicate predicate=#&lt;Method: Module(Dry::Logic::Predicates::Methods)#filled?&gt; options={:args=&gt;[]}&gt;] options={:name=&gt;:password, :evaluator=&gt;#&lt;Dry::Logic::Evaluator::Key path=[:password]&gt;, :path=&gt;:password, :id=&gt;:password}&gt;] options={:id=&gt;:password}&gt;}&gt;], @final=#&lt;Dry::Validation::BuildErrors:0x000000000524f8d8&gt;&gt;&gt;}&gt; &gt;
  </code></pre>
  
  <p>The password of the model is not encrypted in the database, I believe this is because Contract::Build is fetching the password from the params and not the model. </p>
  
  <p>Any thoughts?</p>