开发者

Is it possible to unload an ActiveRecord association?

开发者 https://www.devze.com 2023-02-18 00:25 出处:网络
I encountered a situation where a model being saved in flash caused a marshall data too short error, and discovered that the reason for this is that a huge association was being loaded and then when p

I encountered a situation where a model being saved in flash caused a marshall data too short error, and discovered that the reason for this is that a huge association was being loaded and then when put into the session the data was too large for the field.

My classes look something like this:

class Location < ActiveRecord::Base
  belongs_to :country
  belongs_to :state
  belongs_to :city
end

class Country < ActiveRecord::Base
  has_many :states
  has_many :locations
end

class State < ActiveRecord::Base
  belongs_to :country
  has_many :cities
  has_many :locations
end

class City < ActiveRecord::Base
  belongs_to :state
  has_many :locations
end

Unfortunately, the validation in Location accesses self.state.cities, which loads all the cities for that state into memory (in this case, over 1000 records). As such, when the Location object is passed 开发者_如何转开发through flash, it causes the above error.

I realize that the code can be refactored to not access the association (in fact, that's what I've done at the moment), but I was wondering if there was any way to unload the association data from memory (without deleting it from the database, of course).

This project is using Rails 2.3.4 and unfortuately I am unable to upgrade it at the moment.


Part 1: Solution to the stated problem:

To empty the loaded association data, use the target method on the association:

location.state.cities.target=[]

If you access the cities now:

location.state.cities
=> []

Part 2: Clumsy way to avoid the problem:

Avoid loading the association while accessing cities. Use

self.state.cities.all 

Instead of

self.state.cities

Part 3: Something smells fishy:

Why are you storing objects in to flash? Flash is generally meant for sending text messages. If you assign non strings to flash you will run in to the cookie size limit in no time.

Also when you are validating why do you need to load all the cities? Does this mean you are validating in Ruby? Can you post the validation code. In most cases you can optimize this by moving validation to DB.

Edit: Extended the answer based on the comment

I follow this pattern in Rails 2.3.x. The variables I want to access in the view associated with edit action is always a subset of variables available in update action.

class ProductsController < ApplicationController

  before_filter :init_data, :only => [:new, :create, :edit, :update, 
                                      :destroy, :show]
  def update
    @product.attributes = params[:product]
    if @product.save
      flash[:notice] = "Successfully saved the product."
      redirect_to  product_path(@product)
    else
      render :action => 'edit'
    end
  end

private
  def init_data
    switch(action.to_sym)
      when :new, :create
        @product = Product.new(params[:product])
      when :edit, update, :destroy, :show 
        @product = Product.find(params[:id])
    end
  end    
end
0

精彩评论

暂无评论...
验证码 换一张
取 消