How to implement update controller method

14,371

There are two issues:

  1. You need to save your updated object
  2. You should be doing this within the bounds of resources (although not essential)

Resourceful

The first step is to ensure you're using this with the correct routes etc.

You shouldn't have an add_images method in your controller - you could achieve what you need with edit/update:

#config/routes.rb
resources :food_items do
    resources :images #-> if necessary, this should be its own controller rather than adding needless methods to your other controller
end

You should use the following controller setup:

#app/models/food_item.rb
class FoodItem < ActiveRecord::Base
   accepts_nested_attributes_for :food_images
end

#app/controllers/food_items_controller.rb
class FoodItemsController < ApplicationController
   def edit
      @food_item = FoodItem.find params[:id]
      @food_item.food_images.build
   end

   def update
      @food_item = FootItem.find params[:id]
      respond_to do |format|
        if @food_item.update food_item_params
           ...
        end
      end
   end

   private

   def food_item_params
     params.require(:food_items).permit(:name, :category, :description, food_images_attributes: [:id, :food_item_id, :avatar]) #-> this is enough (no need to "whitelist")
   end
end

This will give you the ability to load the following:

#url.com/food_items/:id/edit
#app/views/food_items/edit.html.erb
<%= form_for @food_item do |f| %>
= form_for @food_item, html: { :multipart => true } do |f|
  = f.label :title
  = f.text_field :title
 = f.fields_for :food_images do |p|
     = p.label :avatar
     = p.file_field :avatar
.actions
   = f.submit
<% end %>

This will submit to the "update" method, which should save the required object for you.

You should only upload one file at a time

If you need to upload multiple files, you'll need to use a gem such as cocoon to add them. Rails is great but not magical -- it has to build a single object with each fields_for.

I can explain more about this if required.

--

To give you context on why you should be using the edit / update methods for this, you need to look up the resourceful principle for object orientated programming.

enter image description here

This is built on the "resources" principle put forward at the inception of HTTP -- a standardized set of technologies which allow browsers to send and retrieve data from servers.

In short, it means there are certain conventions you should abide by to keep your app extensible.

Because Ruby/Rails is object orientated, everything you do in a well-tailored application should revolve around objects. Like resources, these allow you to create a system which is both flexible and extensible if done properly.

Thus, with your code, you have to remember that you're trying to add an image to the food items object. You should therefore be editing the food items object, updating it with the extra image; which the above code will help you achieve.

Share:
14,371
Dengke Liu
Author by

Dengke Liu

Updated on June 04, 2022

Comments

  • Dengke Liu
    Dengke Liu about 2 years

    I am working on web app development using ruby on rails. I want to enable users to upload images for their favorite food. I have food_item model and a food_image model. In the food_item model:

    has_many :food_images
    has_many :food_portions #this is the work done by another teammate
    

    I also define in the food_item controller:

    def food_item_params
      params.require(:food_items).permit(:name, :category, :description, food_images_attributes: [:id, :food_item_id, :avatar]).tap do |whitelisted|
      whitelisted[:portion] = params[:food_items][:portion]
      whitelisted[:price] = params[:food_items][:price]
    end