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

时间:2011-12-07 17:43:00

标签: validation ruby-on-rails-3.1 model-associations

我有以下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实例。然后我必须在联系人和地址上更新update_attributes然后

@hotel.save :validate => false

确保原始表单数据按预期完全保存。

毫无疑问,这是一段非常糟糕的代码。谁能告诉我如何清理它?

2 个答案:

答案 0 :(得分:0)

您可以使用过滤器,即after_create来调用关联的模型,以在保存@hotel变量后创建关联的记录。

我碰巧遇到了同样的问题,这是我的解决方案。对不起,经过这么长时间这可能没有用,但对未来的用户来说这将是件好事。

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应该属于模型。然后,您可以使用edit操作让用户“创建”银行帐户条目。使用此功能,您只需要标准的创建操作(例如,由rails g scaffold_controller生成)。

更新:我在回答之后重新阅读了您的问题,发现自己更加困惑。我假设您要呈现一个表单,其中不希望用户立即进入银行帐户,而是稍后在另一页面上进行编辑。

答案 1 :(得分:0)

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