开发者

setting activerecord attribute based on virtual attributes

开发者 https://www.devze.com 2023-02-09 20:56 出处:网络
i have an attribute called dimensions which i want to set based on my width, height, and depth attributes.

i have an attribute called dimensions which i want to set based on my width, height, and depth attributes.

for example, i want to do ShippingProfile.find(1).width = 4, and have it save to dimensions as {:width => 4, :height => 0, :depth => 0}`

is this possible?

class ShippingProfile < ActiveRecord::Base
  after_initialize :set_default_dimensions

  serialize :dimensions, Hash

  attr_accessor :width, :height, :depth
  attr_accessible :width, :height, :depth, :dimensions

  private

    def set_default_dimensions
      self.dimensions ||= {:开发者_如何学JAVAwidth => 0, :height => 0, :depth => 0}
    end  
end


Very much so, all you need to do is use a callback to set the value of self.dimensions:

class ShippingProfile < ActiveRecord::Base
  after_initialize :set_default_dimensions
  after_validation :set_dimensions

  serialize :dimensions, Hash

  attr_accessor :width, :height, :depth
  attr_accessible :width, :height, :depth, :dimensions

  private

  def set_default_dimensions
    self.dimensions ||= {:width => 0, :height => 0, :depth => 0}
  end

  def set_dimensions
    self.dimensions = { 
      :width  => self.width || self.dimensions[:width],
      :height => self.height || self.dimensions[:height],
      :depth  => self.depth || self.dimensions[:depth],
    }
  end
end

You need to use self.foo || self.dimensions[:foo] to ensure that you preserve any existing values already set in the hash. Why? Your dimension attributes (I'm assuming) aren't being persisted in the database - you're using attr_accessor, rather than setting them up as fields in your table.

As an aside, I think you're going about your model design the wrong way. By storing the dimensions as a hash in the database, not only do you lose the ability to query based on those attributes, but you add a level of fragility you don't need.

If you are storing your individual dimension attributes as separate fields, then you're introducing redundancy and complexity. You would be better served by having the three attributes as fields in your database (if you aren't already), then generating the dimensions hash on the fly when it's needed:

class ShippingProfile < ActiveRecord::Base
  def dimensions
    { :width => self.width, :height => self.height, :depth => self.depth }
  end
end

This way, you retain the functionality and gain some flexibility.


ShippingProfile.find(1).dimensions[:width] = 4


You can use a class in serialize, so

class ShippingProfile < ActiveRecord::Base
  serialize :dimensions, Dimensions
end

class Dimensions
  attr_accessor :width, :height,:depth

  def initialize
    @width = 0
    @height = 0
    @depth = 0
  end

  def volume
    width * height * depth
  end
end

Now you can do ShippingProfile.dimensions.width = 1 and later ShippingProfile.dimension.volume etc..

A model would be a richer representation than a Hash

0

精彩评论

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