英文:
Trailblazor operation -> collection :attribute(has_many through association) with populator -> How to populate the Reform::Form form array of slugs?
问题
以下是您要翻译的内容:
"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."
英文:
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.
答案1
得分: 2
首先,正如你提到的,acquires_from_companies
数组位于 options
参数中,所以你可以使用整个参数 options
,而不是参数中的 fragment
键。
在选项中会有一个 :doc
键,其中包含了所有的参数。
类似下面这样的方式,使用两个选项:
- 更改模型
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
上述两个示例中的 model
和 self
的区别是...
当你选择 model.attribute
时
你直接更改了这5个步骤,因此验证可能会因为参数中没有正确的值而失败。因为你已经更新的是模型属性而不是参数。
当你选择 self.attribute
时
你在第2步中进行更改。
你跟随流程,所有后续步骤都会在参数中具有更新后的值。
我建议更改合同/参数,而不是模型。
但只是为了分享,我也分享了使用模型的选项。
无论如何,在填充器中应避免对模型进行更新。
但如果你只是不需要验证并且不关心中间步骤,你可以选择模型更新选项。
Trailblazer 是一个很棒的 gem,使用它后,你可能不会再喜欢普通的结构了。
英文:
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.
- change the model
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']
- change the contract
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.
- Get the model object
- Build nested form tree
- Update form tree from params
- Run validation
- Assign the attributes to the model
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论