Rails: has_many con dettagli in più?
-
21-09-2019 - |
Domanda
Mentre io non sono un completo newb di Ruby / Rails, sono ancora abbastanza verde e sto cercando di capire come strutturare alcune relazioni modello. L'esempio più semplice che posso pensare è l'idea di "ricette" per cucinare.
Una ricetta è costituita da uno o più ingredienti e la quantità di ogni ingrediente associato. Supponiamo di avere un elenco principale nel database di tutti gli ingredienti. Questo suggerisce due modelli semplici:
class Ingredient < ActiveRecord::Base
# ingredient name,
end
class Recipe < ActiveRecord::Base
# recipe name, etc.
end
Se volevamo solo ad associare ricette con gli ingredienti, che è come simpling come l'aggiunta del belongs_to
e has_many
appropriata.
Ma cosa succede se vogliamo associare informazioni aggiuntive con quel rapporto? Ogni Recipe
ha uno o più Ingredients
, ma vogliamo indicare la quantità del Ingredient
.
Qual è il modo Rails per modellare questo? E 'qualcosa lungo le linee di un has_many through
?
class Ingredient < ActiveRecord::Base
# ingredient name
belongs_to :recipe_ingredient
end
class RecipeIngredient < ActiveRecord::Base
has_one :ingredient
has_one :recipe
# quantity
end
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
end
Soluzione
Ricette e ingredienti hanno un ha e appartiene a molti, ma si desidera memorizzare informazioni aggiuntive per il link.
In sostanza quello che stai cercando è un ricco join modello. Ma, un rapporto has_and_belongs_to_many non è abbastanza flessibile per memorizzare le ulteriori informazioni necessarie. Invece è necessario utilizzare un has_many:. Attraverso relatinship
Questo è come vorrei configurarlo.
colonne ricette: istruzioni
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
end
recipe_ingredients colonne: recipe_id, ingredient_id, la quantità
class RecipeIngredients < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
end
colonne ingrediente: nome
class Ingredient < ActiveRecord::Base
has_many :recipe_ingredients
has_many :recipes, :through => :recipe_ingredients
end
Ciò fornirà una rappresentazione di base di quello che stai cercando di fare. Si consiglia di aggiungere una convalida per RecipeIngredients per garantire che ogni ingrediente è elencata una volta per ogni ricetta, e una funzione di callback per piegare i duplicati in una voce.
Altri suggerimenti
http://railsbrain.com /api/rails-2.3.2/doc/index.html?a=M001888&name=has_and_belongs_to_many
http://railsbrain.com /api/rails-2.3.2/doc/index.html?a=M001885&name=has_many
Come su:
- class Ingrediente (appartiene alla ricetta, ha molti ingredientrecipecounts)
- class Ricetta (ha molti ingredienti, ha molti ingredientrecipecounts)
- class IngredientRecipeCount (appartiene alla ingrediente, appartiene alla ricetta)
Questa non è tanto il modo delle rotaie come solo stabilire un altro rapporto tra i dati nel database. Non è proprio un "ha e appartiene a molti" perché ogni ingrediente ha un solo numero per ogni ricetta, e ogni ricetta un conteggio per ingrediente .. che è lo stesso numero.