根据虚拟属性设置activerecord属性

bre*_*ter 3 activerecord attributes ruby-on-rails

我有一个名为的属性dimensions,我想根据我的设置width,height以及depth属性.

例如,我想这样做ShippingProfile.find(1).width = 4,并将它保存为{:width => 4,:height => 0,:depth => 0}.

这可能吗?

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 ||= {:width => 0, :height => 0, :depth => 0}
    end  
end
Run Code Online (Sandbox Code Playgroud)

Dan*_*ail 7

非常如此,您需要做的就是使用回调来设置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
Run Code Online (Sandbox Code Playgroud)

您需要使用self.foo || self.dimensions[:foo]以确保保留已在哈希中设置的任何现有值.为什么?您的维度属性(我假设)没有在数据库中保留 - 您使用的是attr_accessor,而不是将它们设置为表格中的字段.

顺便说一句,我认为你的模型设计是错误的.通过将维度存储为数据库中的哈希,不仅会失去基于这些属性进行查询的能力,而且还会增加您不需要的脆弱程度.

如果你存储您的个人维度属性作为单独的领域,那么你引入冗余和复杂性.将三个属性作为数据库中的字段(如果您还没有)可以更好地服务,然后在需要时动态生成维度哈希:

class ShippingProfile < ActiveRecord::Base
  def dimensions
    { :width => self.width, :height => self.height, :depth => self.depth }
  end
end
Run Code Online (Sandbox Code Playgroud)

这样,您可以保留功能并获得一些灵活性.