How to handle nested collections of looked up objects?
Look at this form:

I have 6 different types of objects we can look up shows, brands, etc. Each one is represented by an ID. The parent object I'm creating is a TailoredAudience.
I wrote the following test:
RSpec.describe TailoredAudience::Create do
let(:valid_params) do
{tailored_audience: {
user_account_id: 4,
name: "Morning People",
shows: [show_id: "7168f630-daec-11e0-9b8e-40402761cfca"]}
}
end
it "creates a new tailored audience" do
model = TailoredAudience::Create[valid_params].model
expect(model).to be_persisted
end
end
The ::Create operation is implemented very simply:
require "tailored_audience"
class TailoredAudience < Sequel::Model(RDB[:tailored_audiences])
class Create < Trailblazer::Operation
include CRUD
model TailoredAudience, :create
contract do
property :name, validates: { presence: true, length: { minimum: 1 } }
property :user_account_id, validates: { presence: true }
collection :shows do
property :show_id, validates: { presence: true }
end
# similarly for brands, show categories, etc.
end
def process(params)
validate(params[:tailored_audience]) do |f|
f.save
end
end
end
end
This fails with the following backtrace:
1) TailoredAudience::Create creates a new tailored audience
Failure/Error: model = TailoredAudience::Create[valid_params].model
RuntimeError:
[Reform] Your :populator did not return a Reform::Form instance for `shows`.
# /home/francois/.bundler/ruby/1.9.1/reform-7657fd317754/lib/reform/form/populator.rb:40:in `handle_fail'
# /home/francois/.bundler/ruby/1.9.1/reform-7657fd317754/lib/reform/form/populator.rb:26:in `call'
# /var/lib/gems/1.9.1/gems/uber-0.0.13/lib/uber/options.rb:85:in `callable!'
# /var/lib/gems/1.9.1/gems/uber-0.0.13/lib/uber/options.rb:70:in `evaluate_for'
# /var/lib/gems/1.9.1/gems/uber-0.0.13/lib/uber/options.rb:60:in `evaluate'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/binding.rb:130:in `evaluate_option'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:76:in `instance_for'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:62:in `create_object'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:21:in `call'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:98:in `deserialize!'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:90:in `block in call'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:86:in `each'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:86:in `each_with_index'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/deserializer.rb:86:in `call'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/populator.rb:49:in `deserialize'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/populator.rb:21:in `call'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/binding.rb:88:in `read_fragment'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/binding.rb:67:in `block in uncompile_fragment'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/binding.rb:123:in `evaluate_option'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/binding.rb:66:in `uncompile_fragment'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/mapper.rb:77:in `uncompile_fragment'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/mapper.rb:38:in `deserialize_property'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/mapper.rb:18:in `block in deserialize'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/mapper.rb:17:in `each'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/mapper.rb:17:in `deserialize'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable.rb:41:in `update_properties_from'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/hash/allow_symbols.rb:10:in `update_properties_from'
# /home/francois/.bundler/ruby/1.9.1/representable-dbf0cb4fa346/lib/representable/hash.rb:28:in `from_hash'
# /home/francois/.bundler/ruby/1.9.1/reform-7657fd317754/lib/reform/form/validate.rb:55:in `deserialize'
# /home/francois/.bundler/ruby/1.9.1/reform-7657fd317754/lib/reform/form/validate.rb:25:in `validate'
# /home/francois/.bundler/ruby/1.9.1/trailblazer-6646e5f5e227/lib/trailblazer/operation.rb:126:in `validate_contract'
# /home/francois/.bundler/ruby/1.9.1/trailblazer-6646e5f5e227/lib/trailblazer/operation.rb:116:in `validate'
# /home/francois/.bundler/ruby/1.9.1/trailblazer-6646e5f5e227/lib/trailblazer/operation/crud.rb:41:in `validate'
# ./app/concepts/tailored_audience/crud.rb:38:in `process'
# /home/francois/.bundler/ruby/1.9.1/trailblazer-6646e5f5e227/lib/trailblazer/operation.rb:69:in `run'
# /home/francois/.bundler/ruby/1.9.1/trailblazer-6646e5f5e227/lib/trailblazer/operation.rb:39:in `call'
# ./spec/concepts/tailored_audience_crud_spec.rb:14:in `block (2 levels) in <top (required)>'
I found the Populator section on the Reform README, and I tried applying it, but the syntax as shown doesn't work anymore. The lambda receives 4 parameters, amongst other things.
How do I transform a list of IDs into a list of Show instances, and allow my form to save?
Hi Francois, this is described in the first section of the Authentication chapter, and here: http://trailblazerb.org/gems/reform/populators.html#populating-by-id