Rails 3序列化模型字段form_for和field_for不生成正确的名称

时间:2015-01-07 16:12:56

标签: ruby ruby-on-rails-3 haml

我有这个型号:

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按预期工作。

1 个答案:

答案 0 :(得分:0)

以下是所有未正确理解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

这个定义让我可以通过给出一个参数哈希来创建Foo和许多Larodi的{​​{1}}。例如:

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]>...类型的形式,其中index只是一个整数。

请注意,在实施自定义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