0
votes

Yesterday I asked a question about setting up has_and_belongs_to_many relationships between models in Rails. I eventually got those relationships working, however, I realized that I needed to store additional information in my join table, which means I should be using a has_many through relationship with a join model (I presume?).

I now have a Recipe model, Ingredient model, and an Amounts join model. Each Recipe has many Ingredients and vice versa. And each Ingredient in a recipe has a certain Amount in a certain unit type.

Here is my setup so far:

models/recipe.rb

class Recipe < ActiveRecord::Base
  has_many :amounts
  has_many :ingredients, :through => :amounts
end

models/ingredient.rb

class Ingredient < ActiveRecord::Base
  has_many :amounts
  has_many :recipes, :through => :amounts
end

models/amounts.rb

class Amounts < ActiveRecord::Base
  belongs_to :recipes
  belongs_to :ingredients
end

MySQL tables:

$ mysql > show columns from recipes;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | NO   |     | NULL    |                |
| desc       | text         | NO   |     | NULL    |                |
| image_url  | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

mysql> show columns from ingredients;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | NO   |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

mysql> show columns from amounts;
+---------------+--------------+------+-----+---------+----------------+
| Field         | Type         | Null | Key | Default | Extra          |
+---------------+--------------+------+-----+---------+----------------+
| id            | int(11)      | NO   | PRI | NULL    | auto_increment |
| recipe_id     | int(11)      | NO   |     | NULL    |                |
| ingredient_id | int(11)      | NO   |     | NULL    |                |
| amount        | int(11)      | NO   |     | NULL    |                |
| units         | varchar(255) | NO   |     | NULL    |                |
| created_at    | datetime     | NO   |     | NULL    |                |
| updated_at    | datetime     | NO   |     | NULL    |                |
+---------------+--------------+------+-----+---------+----------------+

I think I have the relationships set up correctly...I'm just unsure about how to add to the join model/table correctly and then access those values. For instance, will I be able to call @recipe.ingredients and return all the ingredients associated?

EDIT: I apologize for the confusion over what I am trying to do.

When I was using the has_and_belongs_to_many relationship, I could push to @recipe.ingredients with '<<' and have the join table automatically inserted with the recipe_id and ingredient_id. However, this method doesn't seem to work when using has_many through because of the additional attributes in the join table.

How would I go about creating these associations?

2
This looks good to me. What problems are you having?Matthew Lehner
I think I'm confused about how I create the associations the right way. I have a Create Recipe form where ingredients can be chosen that should be associated with that Recipe. When using has_and_belongs_to_many, I could loop through the selected Ingredients and add each with this line: @recipe.ingredients << ingredient. I don't think that method works with this however, since there is now a join model. I'm not sure how to add them the right way.Christian Benincasa

2 Answers

0
votes

you can read and assign to recipe.ingredients directly and it will automatically write to the join table.

But unlikely you will need it since you need additional info for the amount. You probably will need to update/create recipes with nested attributes for amounts coming from a form.

consider a uniqueness contraint on ingredients per recipe in amount model.

hope this helped

0
votes

Setting up a has_many :through association is some of that Rails magic. You'll have access to all the methods that the has_many association sets up for both the join table, and the related table. Rails will take care of any associations automatically.

Have a look at the Rails guide here.