How to serialize a nested model in Rails?

It is very difficult for me to figure out how to serialize nested model attributes in rails. I have a RecipeTemplate that will store an existing recipe in the template_data attribute. The recipe has nested attributes on two levels.

This is on 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 

The ingredients in the recipe also have nested attributes (SubIngredients).

If I set template_data with such an object:

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

I will get a TypeError, "I can’t dump an anonymous class of a class", which makes sense, since it does not know how to serialize ingredients or subintegrations.

How can you serialize nested attributes in a model so you can use:

  serialize :template_data, Recipe 

Or do I have to serialize the data in some other way and independently perform type safety checks?

Thank you in advance for your help.

+6
source share
2 answers

I see why you want the template itself to be stored inside a serialized column, but you need to manipulate the stored data a bit more than what this type of column allows. Here is what I will do:

application / 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 

application / 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 

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

Then to create and use the template:

 # 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 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 

The difference is that you use a serialized column to store the hash for use in the Recipe Competition. If you just wanted to serialize the object, the other posters are correct - just link the object.

+1
source

Why don't you just save the field in your RecipeTemplate with the label recipe_id

and associate this with the recipe instead of trying to serialize the recipe object?

-2
source

Source: https://habr.com/ru/post/892907/


All Articles