trailblazer / reform

Form objects decoupled from models.
https://trailblazer.to/2.1/docs/reform.html
MIT License
2.5k stars 184 forks source link

Error raised when receiving scalar in place of hash #445

Closed agis-theodoropoulos closed 7 years ago

agis-theodoropoulos commented 7 years ago

Complete Description of Issue

I have a nested form which I guard with a :hash? validator. However, passing a scalar value as argument raises an error.

Steps to reproduce

class TheForm < Reform::Form
  property :outer, populate_if_empty: Hash do
    include Disposable::Twin::Property::Struct

    property :inner

    validation do
      required(:inner).filled(:str?)
    end
  end

  validation do
    required(:outer).filled(:hash?)
  end
end

And then:

  the_model = Struct.new(:outer).new

  # works fine
  TheForm.new(the_model).validate(outer: { inner: "7847be0d04b76a783b02b32486daa700" })

  # throws NoMethodError: undefined method `keys' for "7847be0d04b76a783b02b32486daa700":String
  TheForm.new(the_model).validate(outer: "7847be0d04b76a783b02b32486daa700")

Expected behavior

Actual behavior

A NoMethodError exception is raised with the message:

undefined method `keys' for "7847be0d04b76a783b02b32486daa700":String

System configuration

Reform version: 2.2.4

Full Backtrace of Exception (if any)

     Failure/Error: TheForm.new(the_model).validate(outer: "7847be0d04b76a783b02b32486daa700")

     NoMethodError:
       undefined method `keys' for "7847be0d04b76a783b02b32486daa700":String
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/hash/allow_symbols.rb:20:in `stringify_keys'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/hash/allow_symbols.rb:10:in `update_properties_from'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/hash.rb:30:in `from_hash'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/reform-2.2.4/lib/reform/form/validate.rb:28:in `deserialize'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/reform-2.2.4/lib/reform/form.rb:14:in `block in <class:Form>'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/pipeline.rb:18:in `evaluate'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/pipeline.rb:10:in `block in call'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/pipeline.rb:9:in `each'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/pipeline.rb:9:in `inject'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/pipeline.rb:9:in `call'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/binding.rb:37:in `uncompile_fragment'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable.rb:53:in `block in call'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable.rb:51:in `each'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable.rb:51:in `call'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable.rb:70:in `representable_map!'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable.rb:37:in `update_properties_from'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/hash/allow_symbols.rb:10:in `update_properties_from'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/representable-3.0.4/lib/representable/hash.rb:30:in `from_hash'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/reform-2.2.4/lib/reform/form/validate.rb:28:in `deserialize'
     # /home/atheodor/.rvm/gems/ruby-2.4.1/gems/reform-2.2.4/lib/reform/form/validate.rb:21:in `validate'
fran-worley commented 7 years ago

Disposable struct is deprecated, what you want is to use hash fields:

class TheForm < Reform::Form
  include Disposable::Twin::Property::Hash

  property :outer, field: :hash do
    property :inner
  end

  # you can do your validations like this too....
  required(:outer).filled.schema do 
    required(:inner).filled
  end
end
agis-theodoropoulos commented 7 years ago

Wow! Thanks, I missed this in the docs.