I'm using gem trailblazer
.
I have following structure.
Following two models
class Company
has_many :acquirable_source_companies,
class_name: 'AcquirableSourceCompany',
foreign_key: 'acquirer_company_id',
inverse_of: :acquirer_company
has_many :acquires_from_companies, through: :acquirable_source_companies, source: :acquires_from_company
end
class AcquirableSourceCompany
belongs_to :acquirer_company,
class_name: 'Company',
foreign_key: 'acquirer_company_id',
inverse_of: :acquires_from_companies
belongs_to :acquires_from_company, class_name: 'Company', foreign_key: 'source_company_id'
end
Now I just want to use multi select to select acquirable companies when I edit parent
companies.
In the frontend I'm having following
f.input :acquires_from_companies,
as: :select,
collection: ::Company.where.not(type: :parent).pluck(:slug),
include_blank: true,
selected: @company.acquires_from_companies.pluck(:slug),
input_html: { multiple: true, class: 'select2' }
Now when I save this form, it passes the array of string in following format.
Parameters: {"authenticity_token"=>"<token>", "company"=>{"acquires_from_companies"=>["", "child_1", "child_2", "child_3"], ...}, id: 1 }
the operation class looks like following
module Companies
module Operations
class Update < ParentClass
include Model
model ::Company
contract do
collection :acquires_from_companies
end
end
end
end
And the collection have array of string.
What is best way to convert it to Reform::Form
or ActiveRecord collection.
before the parameter get validated.
I've tried following
contract do
collection :acquires_from_companies, populator: :companies
def companies(fragment:, **)
acquires_from_companies = acquires_from_companies.push(Company.find_by(slug: fragment))
end
end
But that empty string is not working out.
Also if I somehow manage to get rid of empty string from array. Should I build company object one by one or all together.
for any option either one by one or all together what should be the ideal implementation?
Also please let me know if more details are required to understand the question.
First as you mentioned the array of slugs is in acquires_from_companies
so you can do is use the whole argument options
instead of on key fragment
in the argument.
There will be a :doc
present in the options, and that have all the parameters.
Something like the following with two options.
contract do
collection :acquires_from_companies, populator: :companies
def companies(options)
model.acquires_from_companies = Company.where(slug: options[:doc]['acquires_from_companies'])
end
end
options[:doc]['acquires_from_companies']
contract do
collection :acquires_from_companies, populator: :companies
def companies(options)
self.acquires_from_companies = Company.where(slug: options[:doc]['acquires_from_companies'])
end
end
These could be normal flow of steps in a trailblazer operation.
The difference between model
and self
in the above two examples is…
When you choose model.attribute
You directly change the 5 steps so validation might fail because of not having the right value in the params. Because what you have updated is model attribute not params.
When you choose the self.attribute You change at the 2nd step. You go with flow, and all further steps will have updated value in the params.
I would suggest changing the contract/params instead of the model.
But just for sake of sharing I’m sharing the option of model as well.
In any case, model updates should be avoided in the populator. But you just don’t have validation and don’t care about in between steps, you can go with the model update option.
Trailblazer is an awesome gem, you won’t like normal structure after that.