Как сериализовать вложенную модель в Rails? - PullRequest
6 голосов
/ 17 июля 2011

Мне очень трудно понять, как сериализовать вложенные атрибуты модели в рельсах.У меня есть RecipeTemplate, который будет хранить уже существующий рецепт в своем атрибуте template_data.Рецепт имеет вложенные атрибуты глубиной два уровня.

Это на рельсах 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

Ингредиенты в рецепте также имеют вложенные атрибуты (SubIngredients).

Если я установлю template_data с помощью объекта, подобного так:

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

Я получу TypeError "не могу сбросить анонимный класс Class", который имеет смысл, так как он не знаеткак сериализовать Ingredients или SubIngredients.

Как вы можете сериализовать вложенные атрибуты в модели, чтобы вы могли использовать:

 serialize :template_data, Recipe

Или мне нужно сериализовать данные в некоторых другихи сам выполняешь проверки безопасности типа?

Заранее благодарен за любую помощь

Ответы [ 2 ]

1 голос
/ 17 декабря 2012

Я понимаю, почему вы хотите, чтобы сам шаблон хранился внутри сериализованного столбца, но вам нужно немного больше манипулировать сохраняемыми данными, чем это разрешено столбцом этого типа.Вот что я бы сделал:

app / models / 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

app / models / 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

app / models / ингридиент.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

Разница в том, что вы используете сериализованный столбец для хранения хэша для использования в конструкторе рецепта.Если вы просто хотели сериализовать объект, другие плакаты верны - просто свяжите объект.

0 голосов
/ 15 января 2012

Почему бы вам не оставить в своей модели RecipeTemplate поле с меткой recipe_id

и связать его с рецептом, а не пытаться сериализовать объект рецепта?

...