Rails 3 序列化模型字段 form_for 和 field_for 未生成正确的名称
Rails 3 serialized model field form_for and field_for not generating correct name
我有这个型号:
class CompanyCrawler < ActiveRecord::Base
....
serialize :entry_pages, Array
def entry_page_objects
entry_pages.map { |url| EntryPage.new(url) }
end
def entry_page_objects_attributes=(attributes)
# ...
end
....
end
渲染模型的形式:
.....
%p
%p
= crawler_form.label 'Entry pages'
= crawler_form.text_area :entry_pages_text, size: '80x6'
%ul.entry-pages
= crawler_form.fields_for :entry_page_objects do |entry_page_field|
%li=entry_page_field.text_field :url, size: 80
%a{href: '#', class: 'add-button'} Add Entry Page
我遇到的问题是表单错误地呈现了 entry_page_object
输入名称(例如 company_crawler[entry_page_objects_attributes][0][url]
而不是 company_crawler[entry_page_objects][0][url]
)。我真的不知道该怎么做,我已经阅读了文档,示例中说只要定义 attr_attributes=(attributes)
和 persisted?
我就可以将 fields_for
用于集合,就像它们是用 accept_nested_fields
.
定义的关联
我见过不同的解决方案,比如将 String
'entry_page_objects[]'
给 fields_for
,但我想与 rails 命名约定保持一致,我知道我可以使用 form_tag
而不是 form_for
但我想让 fields_for
按预期工作。
这里有一些信息供所有没有正确理解 nested_attributes
工作原理的人使用,比如我。
我报告的问题实际上是它应该如何工作。当我们有,比方说,这个模型:
class Foo < ActiveRecord::Base # it has name attribute
has_many :larodis
accepts_nested_attributes_for :larodi
end
class Larodi < ActiveRecord::Base # it has name attribute
belongs_to :foo
end
这个定义让我可以通过提供参数的散列来创建具有许多 Larodi
的 Foo
。例如:
x = Foo.create(name: 'Josh', larodi_attributes: [ {name: 'Wayne'} ]
x.larodis.map(&:name) # ['Wayne']
现在是 #field_for
了解我们是否有嵌套属性的部分。我们通过寻找 name_attributes=
方法来检查这一点。如果它被定义 #fields_for
生成类型 <input ... name=object[name][INDEX][method]>...
的形式,其中索引只是一个整数。
请记住,在实现自定义 name_attibutes(attributes)
时,您必须检查属性类型 - 它可以是 Array
就像示例一样,它可以是 Hash
这种类型:
{ 1 => { ... } , 2 => { ... } }
就像表示数组的散列一样,其中键是索引,值是该索引的值。
答案看起来像这样:
_form.html.haml
....
= crawler_form.fields_for :entry_pages do |entry_page_field|
%li
=entry_page_field.text_field :url, size: 80
...
company_crawler.rb
class CompanyCrawler < ActiveRecord::Base
....
serialize :entry_pages, Array
def entry_pages_attributes=(attributes)
self.entry_pages = attributes_collection(attributes).map do |attribute|
EntryPage.new(attribute[:url])
end
end
def entry_pages=(entry_pages)
entry_pages = entry_pages.map do |entry_page|
cast_entry_page_to_entry_page_object(entry_page)
end
write_attribute(:entry_pages, entry_pages)
end
...
private
def attributes_collection(attributes)
case attributes
when Array
attributes
when Hash
attributes.values
end
end
def cast_entry_page_to_entry_page_object(entry_page)
case entry_page
when String
EntryPage.new(entry_page)
when EntryPage
entry_page
end
end
end
为清楚起见,我删除了 entry_page_objects
并仅使用 entry_pages
。
我有这个型号:
class CompanyCrawler < ActiveRecord::Base
....
serialize :entry_pages, Array
def entry_page_objects
entry_pages.map { |url| EntryPage.new(url) }
end
def entry_page_objects_attributes=(attributes)
# ...
end
....
end
渲染模型的形式:
.....
%p
%p
= crawler_form.label 'Entry pages'
= crawler_form.text_area :entry_pages_text, size: '80x6'
%ul.entry-pages
= crawler_form.fields_for :entry_page_objects do |entry_page_field|
%li=entry_page_field.text_field :url, size: 80
%a{href: '#', class: 'add-button'} Add Entry Page
我遇到的问题是表单错误地呈现了 entry_page_object
输入名称(例如 company_crawler[entry_page_objects_attributes][0][url]
而不是 company_crawler[entry_page_objects][0][url]
)。我真的不知道该怎么做,我已经阅读了文档,示例中说只要定义 attr_attributes=(attributes)
和 persisted?
我就可以将 fields_for
用于集合,就像它们是用 accept_nested_fields
.
我见过不同的解决方案,比如将 String
'entry_page_objects[]'
给 fields_for
,但我想与 rails 命名约定保持一致,我知道我可以使用 form_tag
而不是 form_for
但我想让 fields_for
按预期工作。
这里有一些信息供所有没有正确理解 nested_attributes
工作原理的人使用,比如我。
我报告的问题实际上是它应该如何工作。当我们有,比方说,这个模型:
class Foo < ActiveRecord::Base # it has name attribute
has_many :larodis
accepts_nested_attributes_for :larodi
end
class Larodi < ActiveRecord::Base # it has name attribute
belongs_to :foo
end
这个定义让我可以通过提供参数的散列来创建具有许多 Larodi
的 Foo
。例如:
x = Foo.create(name: 'Josh', larodi_attributes: [ {name: 'Wayne'} ]
x.larodis.map(&:name) # ['Wayne']
现在是 #field_for
了解我们是否有嵌套属性的部分。我们通过寻找 name_attributes=
方法来检查这一点。如果它被定义 #fields_for
生成类型 <input ... name=object[name][INDEX][method]>...
的形式,其中索引只是一个整数。
请记住,在实现自定义 name_attibutes(attributes)
时,您必须检查属性类型 - 它可以是 Array
就像示例一样,它可以是 Hash
这种类型:
{ 1 => { ... } , 2 => { ... } }
就像表示数组的散列一样,其中键是索引,值是该索引的值。
答案看起来像这样:
_form.html.haml
....
= crawler_form.fields_for :entry_pages do |entry_page_field|
%li
=entry_page_field.text_field :url, size: 80
...
company_crawler.rb
class CompanyCrawler < ActiveRecord::Base
....
serialize :entry_pages, Array
def entry_pages_attributes=(attributes)
self.entry_pages = attributes_collection(attributes).map do |attribute|
EntryPage.new(attribute[:url])
end
end
def entry_pages=(entry_pages)
entry_pages = entry_pages.map do |entry_page|
cast_entry_page_to_entry_page_object(entry_page)
end
write_attribute(:entry_pages, entry_pages)
end
...
private
def attributes_collection(attributes)
case attributes
when Array
attributes
when Hash
attributes.values
end
end
def cast_entry_page_to_entry_page_object(entry_page)
case entry_page
when String
EntryPage.new(entry_page)
when EntryPage
entry_page
end
end
end
为清楚起见,我删除了 entry_page_objects
并仅使用 entry_pages
。