如何在Rails中序列化嵌套模型?

时间:2011-07-16 20:03:34

标签: ruby-on-rails serialization activerecord nested-attributes

我很难确定如何在rails中序列化模型的嵌套属性。我有一个RecipeTemplate,它将已存在的Recipe存储在它的template_data属性中。 Recipe有两个级别的嵌套属性。

这是在rails 3.1.0.rc4

class RecipeTemplate < ActiveRecord::Base
  serialize :template_data, Recipe
 ...
end

class Recipe < ActiveRecord::Base
  has_many :ingredients
  accepts_nested_attributes_for :ingredients
 ...
end

Recipe中的成分也有嵌套属性(SubIngredients)。

如果我使用如下对象设置template_data:

Recipe.includes(:ingredients => [:sub_ingredients]).find(1)

我会得到一个TypeError“无法转储匿名类Class”,这是有道理的,因为它不知道如何序列化Ingredients或SubIngredients。

如何序列化模型中的嵌套属性,以便您可以使用:

 serialize :template_data, Recipe

或者我是否必须以其他方式序列化数据并自行执行类型安全检查?

提前感谢您提供任何帮助

2 个答案:

答案 0 :(得分:1)

我可以看到为什么你希望模板本身存储在一个序列化列中,但是你需要比那种类型的列所允许的更多地存储所存储的数据。这就是我要做的事情:

应用程序/模型/ recipe_template.rb

class RecipeTemplate < ActiveRecord::Base
  serialize :template_data

  attr_accessible :name, :recipe

  def recipe=(r)
    self.template_data = r.serializable_hash_for_template
  end

  def recipe
    Recipe.new(template_data)
  end
end

应用程序/模型/ recipe.rb

class Recipe < ActiveRecord::Base
  has_many :ingredients, as: :parent
  accepts_nested_attributes_for :ingredients

  attr_accessible :name, :ingredients_attributes

  def serializable_hash_for_template(options={})
    options[:except] ||= [:id, :created_at, :updated_at]
    serializable_hash(options).tap do |h|
      h[:ingredients_attributes] = ingredients.map(&:serializable_hash_for_template)
    end
  end
end

应用程序/模型/ ingredient.rb

class Ingredient < ActiveRecord::Base
  belongs_to :parent, polymorphic: true
  has_many :sub_ingredients, class_name: 'Ingredient', as: :parent
  accepts_nested_attributes_for :sub_ingredients

  attr_accessible :name, :sub_ingredients_attributes

  def serializable_hash_for_template(options={})
    options[:except] ||= [:id, :parent_id, :parent_type, :created_at, :updated_at]
    serializable_hash(options).tap do |h|
      h[:sub_ingredients_attributes] = sub_ingredients.map(&:serializable_hash_for_template)
    end
  end
end

然后创建并使用模板:

# create a recipe to use as a template
taco_meat = Ingredient.create(name: "Taco Meat")
taco_seasoning = taco_meat.sub_ingredients.create(name: "Taco Seasoning")
sams_tacos = Recipe.create(name: "Sam's Tacos")
sams_tacos.ingredients << taco_meat

# create a template from the recipe
taco_recipe = RecipeTemplate.create(name: "Taco Recipe", recipe: sams_tacos)

# build a new recipe from the template
another_taco_recipe = taco_recipe.recipe

不同之处在于您使用序列化列来存储要在Recipe构造函数中使用的Hash。如果你只想序列化对象,其他海报是正确的 - 只需关联一个对象。

答案 1 :(得分:-2)

为什么不在RecipeTemplate模型中使用标签recipe_id

保留一个字段

并将其链接到配方而不是尝试序列化配方对象?