我有以下4种型号的
Hotel (name)
has_one :address
has_one :contact
has_one :bank_account
validates_presence_of :name
def build_dependencies
build_contact
build_address
build_bank_account
end
Address (phone, street_address, hotel_id)
belongs_to :hotel
validates_presence_of :phone, :street_address
Contact (name, email, hotel_id)
belongs_to :hotel
validates_presence_of :name, :email
BankAccount (name, number, hotel_id)
belongs_to :hotel
validates_presence_of :name, :number
在用于创建酒店的表格中,我为联系人模型输入姓名和电子邮件,但为地址模型只输入电话。
HotelController#new
@hotel = Hotel.new
@hotel.build_dependencies #this creates empty Contact and Address to generate the form fields
#render the form to create the hotel
HotelController#create
#receive form data
@hotel = Hotel.new
@hotel.build_dependencies
@hotel.save :validate => false
@hotel.attributes = params[:hotel]
@hotel.save :validate => false
这是我创建一家酒店的唯一方法,包括联系方式、地址和空银行账户。我不得不打电话给
@hotel.save :validate => false
第一次用BankAccount、Address、Contact的空白实例保存Hotel实例。然后我必须更新联系人和地址的属性,然后更新
@hotel.save :validate => false
以确保原始表单数据按预期完全保存。
毫无疑问,这是一段非常糟糕的代码。有人能告诉我怎么清理吗?
保存@hotel
变量后,可以使用一个过滤器,即after_create
来调用关联的模型来创建关联的记录。
我碰巧也面临同样的问题,下面是我的解决方案。很抱歉,这可能在这么长时间后没有帮助,但对未来的用户有好处。
class User < ActiveRecord::Base
has_one :bank_account
# Filter -- After Creation
after_create :create_default_bank_account
def create_default_bank_account
self.build_bank_account
self.bank_account.save(:validate=>false)
# :validate=>false must be called on the bank_account's save. I made the mistake of trying to save the user. =(
end
通过这种方式,您可以从create
操作中删除空行创建,IMHO应该属于Model。然后,您可以使用edit
操作让用户"创建"银行帐户条目。使用它,您只需要一个标准的创建操作(例如由rails g scaffold_controller
生成(。
更新:我在回答完你的问题后重读了一遍,发现自己更加困惑了。我想你想呈现一个表单,其中用户不需要立即输入银行账户,而是稍后在另一个页面上编辑它。
Address
validates_presence_of :phone, :on => :create, :if => proc { |u| u.creating_hotel? }
validates_presence_of :street, :phone, :on => :update
Contact
validates_presence_of :name, :email :on => :update
def creating_hotel?
addressable_type == 'Hotel'
end
用户仅在创建酒店后才能看到:street, :name, :email
字段,在创建过程中才能看到:phone
字段。