Rails改变对象的多态类型

时间:2009-12-07 05:48:48

标签: ruby-on-rails inheritance polymorphism

我们有一个父模型车辆继承来制造类Car,Truck,SUV。在我们的表单中,我们允许用户编辑一堆车辆的数据,每个车辆的一个属性是“类型”的选择菜单。 HTML属性名为vehicle_type,并更新Vehicle Model中的实际Polymorphic类型属性:

  # Get/Set Type bc rails doesnt allow :type to be set in mass
  def vehicle_type
    self.type
  end
  def vehicle_type=(type)
    self.type = type
  end

我们遇到的问题是,当我们在表单数据上调用update_attributes并且现有车辆的类型已经更改时,rails会调用旧类(非新类型)的验证,这会导致错误。我们需要做的是更改vehicle_type时,模型也会更改为新类型。

有办法做到这一点吗?


以下是更新操作(车队has_many车辆):

  # PUT /fleet/1
  # PUT /fleet/1.xml
  def update
    @fleet = Fleet.find(params[:id])

    respond_to do |format|
      if @fleet.update_attributes(params[:fleet])
        flash[:notice] = 'Fleet of vehicles was successfully updated.'
        format.html { render :action => "edit" }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @fleet.errors, :status => :unprocessable_entity }
      end
    end
  end

这是舰队:

class Fleet < ActiveRecord::Base
  has_many :vehicles, :dependent => :destroy, :order => 'position ASC'
  accepts_nested_attributes_for :vehicles,
    :reject_if => proc { |attrs| attrs['name'].blank? },
    :allow_destroy => true

2 个答案:

答案 0 :(得分:2)

您可以使用工厂方法创建正确类型的车辆,然后分配属性。

def Vehicle.factory(type)
   type.constantize.new
end

答案 1 :(得分:0)

当您致电@vehicle.save时,您可以添加false作为跳过验证的第一个参数(@vehicle.save(false))。另一种选择是使用ActiveRecord::Base#update_attribute - 跳过验证。

因此,您可以在不更改类型列的情况下保存模型,然后在同一操作中添加@vehicle.update_attribute(:type, "Truck")。两个SQL查询,但可能对您的情况是必要的。