validar validaciones rails polimorficas formulario asociaciones ruby-on-rails activerecord

ruby-on-rails - polimorficas - validaciones rails



has_many: a través de una asociación has_and_belongs_to_many (4)

Estoy tratando de hacer lo siguiente en un proyecto de Ruby on Rails:

class FoodItem < ActiveRecord::Base has_and_belongs_to_many :food_categories has_many :places, :through => :food_categories end class FoodCategory < ActiveRecord::Base has_and_belongs_to_many :food_items belongs_to :place end class Place < ActiveRecord::Base has_many :food_categories has_many :food_items, :through => :food_category end

Pero llamar al método de instancia some_food_item.places me da el siguiente error:

ActiveRecord::StatementInvalid: PGError: ERROR: column food_categories.food_item_id does not exist LINE 1: ...laces".id = "food_categories".place_id WHERE (("food_cate... : SELECT "places".* FROM "places" INNER JOIN "food_categories" ON "places".id = "food_categories".place_id WHERE (("food_categories".food_item_id = 1))

Lo cual tiene perfecto sentido: debido a las HABTM en FoodItem y FoodCategory, tengo la tabla de asignación llamada food_categories_food_items .

¿Qué tengo que hacer para que some_food_item.places busque correctamente lugares a través de la tabla de asignación en lugar de buscar un food_item_id en la tabla food_categories ?


Esto es correcto, porque no puede realizar "tiene muchos pasos" en una tabla de unión. En esencia, estás tratando de extender la relación un grado más allá de lo que realmente puedes. HABTM (has_and_belongs_to_many) no es una solución muy robusta para la mayoría de los problemas.

En su caso, recomendaría agregar un modelo llamado FoodCategoryItem y cambiar el nombre de su tabla de combinación para que coincida. También necesitarás volver a agregar el campo de la clave principal. Luego configura tus asociaciones modelo así:

class FoodItem < ActiveRecord::Base has_many :food_categories, :through => :food_category_items has_many :places, :through => :food_categories end class FoodCategory < ActiveRecord::Base has_many :food_items, :through => :food_category_items belongs_to :place end class FoodCategoryItems < ActiveRecord::Base belongs_to :food_item belongs_to :food_category end class Place < ActiveRecord::Base has_many :food_categories has_many :food_items, :through => :food_categories end

Tenga en cuenta que también arreglé un error tipográfico en "Lugar -> has_muy: elementos de comida". Esto debería ocuparse de lo que necesita y darle la ventaja adicional de poder agregar funcionalidad a su modelo de "unión" de FoodCategoryItems en el futuro.


Estoy usando Rails 3.2.13 y Rasmus, su configuración original ahora parece funcionar bien en una HABTM.

Sugiero que los usuarios prueben primero antes de intentar una solución alternativa.


Hace unos meses, escribí un artículo sobre esto . En resumen, has_many través de una asociación has_and_belongs_to_many no está permitida por Rails. Sin embargo, puedes simular parcialmente la relación haciendo algo como esto:

class FoodItem < ActiveRecord::Base has_and_belongs_to_many :food_categories named_scope :in_place, lambda{ |place| { :joins => :food_categories, :conditions => {:food_categories => {:id => place.food_category_ids}}, :select => "DISTINCT `food_items`.*" # kill duplicates } } end class FoodCategory < ActiveRecord::Base has_and_belongs_to_many :food_items belongs_to :place end class Place has_many :food_categories def food_items FoodItem.in_place(self) end end

Esto le dará el método some_food_item.places que busca.


Mi primera versión de la respuesta fue incorrecta, pero esta funciona perfectamente. Hice un par de errores tipográficos la primera vez (el peligro de no crear realmente una aplicación para probar) pero esta vez lo verifiqué. Y se necesita un complemento, pero esto es fácil. primero, instala el plugin:

script/plugin install git://github.com/ianwhite/nested_has_many_through.git

Esto instala la solución provisional de Ian White, y funciona a la perfección. Ahora los modelos, copiados directamente de la aplicación de prueba, los configuro para que funcionen:

class FoodItem < ActiveRecord::Base has_many :food_category_items has_many :food_categories, :through => :food_category_items has_many :places, :through => :food_categories end class FoodCategory < ActiveRecord::Base has_many :food_category_items has_many :food_items, :through => :food_category_items belongs_to :place end class FoodCategoryItem < ActiveRecord::Base belongs_to :food_item belongs_to :food_category end class Place < ActiveRecord::Base has_many :food_categories has_many :food_category_items, :through => :food_categories has_many :food_items, :through => :food_category_items end

Ahora las asociaciones "lejanas" funcionan igual de bien. place_instance.food_items y food_item.places funcionan sin problemas, así como las asociaciones más simples involucradas. Solo como referencia, aquí está mi esquema para mostrar dónde van todas las claves foráneas:

create_table "food_categories", :force => true do |t| t.string "name" t.integer "place_id" t.datetime "created_at" t.datetime "updated_at" end create_table "food_category_items", :force => true do |t| t.string "name" t.integer "food_item_id" t.integer "food_category_id" t.datetime "created_at" t.datetime "updated_at" end create_table "food_items", :force => true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end create_table "places", :force => true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end

¡Espero que esto ayude!

ACTUALIZACIÓN: esta pregunta ha surgido algunas veces recientemente. Escribí un artículo, anidando tu has_many: a través de las relaciones , para explicar en detalle. Incluso tiene una aplicación de ejemplo acompañante en GitHub para descargar y jugar.