So I have 2 models. Meal & Food. A meal can hav multiple food items and a food item can be a part of many meals. Basically a many-to-many association. I did that with a has_many :through and the joining model is called MealsFood. When creating a new meal you choose via checkboxes what food items you want to add. The foods table has a column called "calories" and the meals table has a column called "total_calories" where it calculates the sum of all the food items in the meal. The problem is that it isn't working.
Here's what I have so far...
Models
class Meal < ApplicationRecord
belongs_to :user, optional: true
has_many :meal_foods
has_many :foods, through: :meal_foods
def calc_total_calories
self.foods.sum(:calories)
end
end
class MealFood < ApplicationRecord
belongs_to :meal
belongs_to :food
end
class Food < ApplicationRecord
has_many :meal_foods
has_many :meals, through: :meal_foods
end
Meals Controller
class MealsController < ApplicationController
def index
end
def new
@meal = Meal.new
end
def create
@meal = Meal.new(meal_params)
@meal.calc_total_calories
if @meal.save
redirect_to @meal
else
redirect_to root_path
end
end
private
def meal_params
params.require(:meal).permit(:user_id, :meal_type, :date,
:total_calories, :total_carbohydrates, :total_fat, food_ids:[])
end
end
View (new action for meals)
<%= form_for(@meal) do |f| %>
<div class="field">
<%= f.label :meal_type %>
<%= f.select :meal_type, ["Breakfast", "Lunch", "Dinner", "Morning Snack", "Afternoon Snack, Evening Snack"] %>
</div>
<div class="field">
<% Food.all.each do |food| %>
<%= check_box_tag "meal[food_ids][]", food.id %>
<%= food.name %>
<% end %>
</div>
<div class="field">
<%= f.submit class: "button button-highlight button-block" %>
</div>
<% end %>
Notice the def calc_total_calories in the Meal model. It's what I use to calculate the calories, but it doesn't work. I use it in the create method in the Meals controller. Please help! Thanks in advance :)
It doesn't look like you're actually doing anything with calc_total_calories
- it's not assigned to anything in the controller, and not assigning to anything in the model.
You likely want the model method to assign it to something, as in the following:
def calc_total_calories
self.total_calories = self.foods.sum(:calories)
end
That assumes a column on your meal
model called total_calories
.
Does that seem like what you're looking for? Let me know if you've any questions.
I'm thinking, perhaps, that you want to do something like:
class MealsController < ApplicationController
def index
end
def new
@meal = Meal.new
end
def create
@meal = Meal.new(meal_params)
if @meal.save
@meal.update(total_calories: @meal.calc_total_calories)
redirect_to @meal
else
redirect_to root_path
end
end
private
def meal_params
params.require(:meal).permit(:user_id, :meal_type, :date, :total_calories, :total_carbohydrates, :total_fat, food_ids:[])
end
end
In your original code, you're not setting the total_calories
attribute on @meal
, just calling the calc_total_calories
method (which is probably calculating total calories correctly).
In the answer provided by SRack, you're setting, but never saving the total_calories
attribute.
update
will both set and save the attribute.
BTW, you'll want to be sure to think about how you handle changing the foods
associated with a meal
or else your total_calories
may become stale and incorrect.
You could update total calories after saving, in a callback.
after_save :update_calories
def update_calories
update_attributes(total_calories: calc_total_calories)
return true
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.