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
精彩评论