Ada*_*sek 4 ruby forms ruby-on-rails
我正在编写一个名为Person的简单Rails模型has_many :phone_numbers,我试图以复杂的形式保存电话号码,而无需手动编写setter方法.accepts_nested_attributes_for应该做我想要的但我无法让它工作.这是我到目前为止的代码:
移民
class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.string :first_name
t.string :last_name
t.integer :address_id
t.string :email
t.timestamps
end
end
def self.down
drop_table :people
end
end
class CreatePhoneNumbers < ActiveRecord::Migration
def self.up
create_table :phone_numbers do |t|
t.string :number, :limit => 10
t.string :extension, :limit => 5
t.string :description, :null => false
t.integer :telephone_id
t.string :telephone_type
t.timestamps
end
end
def self.down
drop_table :phone_numbers
end
end
Run Code Online (Sandbox Code Playgroud)
楷模
class Person < ActiveRecord::Base
has_one :address, :as => :addressable, :dependent => :destroy
has_many :phone_numbers,
:as => :telephone,
:dependent => :destroy
accepts_nested_attributes_for :phone_numbers
attr_protected :id
validates_presence_of :first_name, :last_name, :email
end
class PhoneNumber < ActiveRecord::Base
attr_protected :id
belongs_to :telephone, :polymorphic => true
end
Run Code Online (Sandbox Code Playgroud)
视图
<% form_for @person, :builder => CustomFormBuilder do |f| %>
<%= f.error_messages %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<% fields_for "person[address]", @person.address, :builder => CustomFormBuilder do |ff| %>
<%= ff.text_field :address_1 %>
<%= ff.text_field :address_2 %>
<%= ff.text_field :city %>
<%= ff.text_field :state %>
<%= ff.text_field :zip %>
<% end %>
<h2>Phone Numbers</h2>
<% @person.phone_numbers.each do |phone_number| %>
<% fields_for "person[phone_numbers][]", phone_number, :builder => CustomFormBuilder do |ff| %>
<%= ff.text_field :description %>
<%= ff.text_field :number %>
<%= ff.text_field :extension %>
<% end %>
<% end %>
<%= f.text_field :email %>
<%= f.submit 'Create' %>
<% end %>
Run Code Online (Sandbox Code Playgroud)
调节器
def new
@person = Person.new
@person.build_address
@person.phone_numbers.build
respond_to { |format| format.html }
end
def create
@person = Person.new(params[:person])
respond_to do |format|
if @person.save
flash[:notice] = "#{@person.name} was successfully created."
format.html { redirect_to(@person) }
else
format.html { render :action => 'new' }
end
end
end
Run Code Online (Sandbox Code Playgroud)
我已经验证正在创建phone_numbers =方法,但该帖子仍会导致:
PhoneNumber(#69088460) expected, got HashWithIndifferentAccess(#32603050)
RAILS_ROOT: H:/projects/test_project
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_proxy.rb:263:in `raise_on_type_mismatch'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations.rb:1290:in `phone_numbers='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `send'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `attributes='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `attributes='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2434:in `initialize'
H:/projects/salesguide/app/controllers/accounts_controller.rb:46:in `new'
H:/projects/test_project/app/controllers/accounts_controller.rb:46:in `create'
Run Code Online (Sandbox Code Playgroud)
我可以通过手动编写phone_numbers =方法来实现这一点,但这会导致巨大的重复工作,我更愿意学习如何做到这一点.谁能看到我做错了什么?
您忘记将fields_for称为人员表单上的方法.否则,您实际上并未在accept_nested_attributes_for上下文中使用fields_for.迈克尔的解决方案试图欺骗Rails将提交视为正确定义的accepts_nested_attributes_for表单.
您尝试执行的操作的正确语法是:
parent_form_object.fields_for id, object_containing_values, {form_for options}, &block
Run Code Online (Sandbox Code Playgroud)
如果您提供符号作为id,您将发现代码看起来更简洁,更简单,包含Person模型中定义的子模型的关联名称.
此外,如果@ person.phone_numbers为空,您正在使用的每个块可能会导致问题.您可以确保至少有一组电话号码字段,其中的行与我使用的行类似
<% @phs = @person.phone_numbers.empty? ? @person.phone_numbers.build : @person.phone_numbers %>
Run Code Online (Sandbox Code Playgroud)
通过所有更正,此代码将按您的要求执行.
视图
<% form_for @person, :builder => CustomFormBuilder do |f| %>
<%= f.error_messages %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<% f.fields_for :address, @person.address, :builder => CustomFormBuilder do |address_form| %>
<%= address_form.text_field :address_1 %>
<%= address_form.text_field :address_2 %>
<%= address_form.text_field :city %>
<%= address_form.text_field :state %>
<%= address_form.text_field :zip %>
<% end %>
<h2>Phone Numbers</h2>
<% @phs = @person.phone_numbers.empty? ? @person.phone_numbers.build : @person.phone_numbers %>
<% f.fields_for :phone_numbers, @phs, :builder => CustomFormBuilder do |phone_number_form| %>
<%= phone_number_form.text_field :description %>
<%= phone_number_form.text_field :number %>
<%= phone_number_form.text_field :extension %>
<% end %>
<%= f.text_field :email %>
<%= f.submit 'Create' %>
<% end %>
Run Code Online (Sandbox Code Playgroud)
您可能会发现在github上查看complex-form-examples存储库以获取工作示例很有用.它还附带了代码,可以从视图/表单中为:has_many关系动态添加新条目.
| 归档时间: |
|
| 查看次数: |
7162 次 |
| 最近记录: |