DEV Community

Cover image for Making a Dynamically Controlled Form: The Backend
Kailana Kahawaii
Kailana Kahawaii

Posted on • Edited on

Making a Dynamically Controlled Form: The Backend

In my last post, I detailed the steps to create a dynamically controlled form component in a React app to create a recipe app. However, that is only half of what we need to save that information to the server. In this post, I’ll go over how to build out a controller in Ruby on Rails that accepts information from a dynamically controlled form.

Creating a recipe

In the controller, write a create method. This create method will be used to create a new recipe.


   def create
       new_recipe_params = {
           title: params[:title],
           summary: params[:summary],
           user_id: params[:user_id]

       }
       recipe = Recipe.create(new_recipe_params)
       create_ingredients(params[:ingredients], recipe.id)
       create_steps(params[:steps], recipe.id)
       render json: { recipe: RecipeSerializer.new(recipe)}
   end
Enter fullscreen mode Exit fullscreen mode

The parameters of a new recipe are as follows:

  • Title
  • Summary
  • User_id
  • Ingredients
  • Steps

As you can see,the method takes in the title, summary, and user_id data and uses helper methods for the ingredients and steps. Also note that there is a private method that handles the form permissions:


private

   def recipe_params
       params.require(:recipe).permit(:title, :summary, :user_id, :steps=> [], :ingredients=>[])
   end

Enter fullscreen mode Exit fullscreen mode

The ingredients are stored in an array from the form on the front end. In order to add them to the recipe, the create_ingredient method goes through that array and creates an ingredient for each element using the name and amount information. Then, the shovel operator adds the new ingredient to to ingredients attribute on recipe.

def create_ingredients(array, id)
       recipe = Recipe.find(id)
       array.each do |ingredient|
           new_ingredient = Ingredient.create({recipe_id: id, name: ingredient[:name], amount: ingredient[:amount]})
           recipe.ingredients << new_ingredient
       end
   end
Enter fullscreen mode Exit fullscreen mode

The create_steps method uses similar logic.

  def create_steps(array, id)
       recipe = Recipe.find(id)
       array.each do |step|
           new_step = Step.create({recipe_id: id, step_summary: step[:step_summary]})
           recipe.steps << new_step
       end
   end
Enter fullscreen mode Exit fullscreen mode

Showing a recipe

A show method allows us to view the newly created recipe.

 def show 
        @recipe = Recipe.find(params[:id])
        if @recipe
            render json: {recipe: @recipe, ingredients: @recipe.ingredients, steps:@recipe.steps }
        else 
            render json: { error: "That recipe does not exist...yet"}, status: :not_acceptable
        end
    end
Enter fullscreen mode Exit fullscreen mode

This works for creating and showing a recipe, but what about editing a recipe?

Editing a recipe

The edit route finds the recipe.

   def edit
       @recipe = Recipe.find(params[:id])
       render json: @recipe
   end
Enter fullscreen mode Exit fullscreen mode

Like the create method, the update method also needs helper methods for the ingredients and steps attributes.

   def update
        @recipe = Recipe.find(params[:id])

        edit_ingredients(params[:ingredients], @recipe.id)
        edit_steps(params[:steps], @recipe.id)

        @recipe.update(recipe_params)

        render json: @recipe
    end
Enter fullscreen mode Exit fullscreen mode

The edit_ingredients method is similar to the create method. First, find the ingredient and then apply the updates to the ingredients that were updated. Again, the updated ingredients are shoveled into recipe.

   def edit_ingredients(array, id)
        recipe = Recipe.find(id)
        if recipe.ingredients
            array.each do |ingredient|
                if ingredient[:id]
                    updated_ingredient = Ingredient.update({recipe_id: id, name: ingredient[:name], amount: ingredient[:amount]}) 
                else 
                   updated_ingredient = Ingredient.create({recipe_id: id, name: ingredient[:name], amount: ingredient[:amount]})
                    recipe.ingredients << updated_ingredient
                end 
            end 
        end
    end
Enter fullscreen mode Exit fullscreen mode

Again, the edit_steps method follows the same pattern as the edit_ingredients method.

   def edit_steps(array, id)
        recipe = Recipe.find(id)
        if recipe.steps
            array.each do |step|
                if step[:id]
                    updated_step = Step.update({recipe_id: id, step_summary: step[:step_summary]}) 
                else 
                    updated_step = Step.create({recipe_id: id, step_summary: step[:step_summary]})
                    recipe.steps << updated_step
                end 
            end 
        end
    end

Enter fullscreen mode Exit fullscreen mode

Delete a recipe

In contrast, the destroy method is relatively simple.

   def destroy 
        @recipe = Recipe.find(params[:id])
        if @recipe 
            @recipe.destroy 
            render json: {message: "Recipe successfully deleted"}
        else 
            render json: {message: "Failed to destroy recipe"}
        end
    end
Enter fullscreen mode Exit fullscreen mode

Conclusion

In order to add information from a dynamically controlled form, use helper methods in your controller to take in information. The edit method will also use helper methods for dynamic information. After implementing the controller logic, a new recipe will be saved to the backend.

Top comments (2)

Collapse
 
almokhtar profile image
almokhtar bekkour

is there any source code there ?

Collapse
 
kahawaiikailana profile image
Kailana Kahawaii