views:

169

answers:

2

We have a parent model Vehicle that is inherited to make classes Car, Truck, SUV. In our form, we allow the user to edit the data for a bunch of Vehicles, and one of the attributes for each vehicle is a select menu for "type". The HTML attribute is named vehicle_type and updates the actual Polymorphic type attribute in the Vehicle Model:

  # 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

The problem we're having is that when we call update_attributes on form data and the type of an existing vehicle has been changed, rails is calling the validation for the old class (not new type) which results in errors. What we need to do is when vehicle_type is changed, that the model is changed to that new type as well.

Is there a way to do this?


Here is the update action (fleet has_many vehicles):

  # 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

Here is Fleet:

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
A: 

When you call @vehicle.save, you could add false as the first parameter to skip validation (@vehicle.save(false)). Another option is to use ActiveRecord::Base#update_attribute -- which skips validation.

So you could save your model without the type column changing, then add a @vehicle.update_attribute(:type, "Truck") in the same action. Two SQL queries, but may be necessary for your situation.

bensie
If i do this though we no longer get any validation for the vehicle right? I was hoping there might be a way to keep validation for the Vehicle (just the right vehicle) and not have to manually iterate through each vehicle to do this (i.e. still use update_attributes).
Lee
+1  A: 

You could use a factory method to create the right type of vehicle, then assign the attributes.

def Vehicle.factory(type)
   type.constantize.new
end
MattMcKnight
This would require ditching the update_attributes method all together though and manually iterating through each Vehicle right? I was hoping there might be a railsy way to leave the update_attribute code (i added the controller code to the question).
Lee
Yeah, I haven't done much with accepts_nested_attributes_for, so I don't know how to modify the methods it creates. (I still use the old "ryanb" method for nested forms.) It's a pretty new feature in Rails and I don't see a ticket in lighthouse. I'll see if I can duplicate it locally and then add a ticket.
MattMcKnight