在创建/更新过程中跳过关联模型中某些成员的验证



我有以下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字段。

最新更新