javascript - Vue.js 和 Rails 的数据库保存问题

标签 javascript ruby-on-rails json vue.js

我正在尝试在 Rails 应用程序中使用 Vue.js 创建嵌套表单。我正在使用嵌套表单将成分保存到食谱中。现在,成分中的所有内容都会保存,但成分名称(从输入字段中获取)除外。如何将此名称字段保存在数据库中?

app/models/ingredient.rb

class Ingredient < ApplicationRecord
  belongs_to :recipe
end

app/models/recipe.rb

class Recipe < ApplicationRecord
  has_many :ingredients
end

app/views/index.html.erb

<h1>Index</h1>
<div id="app">
  {{ message }}
  <form>
    <div class="form-group">
      <label class="form-label">Name</label>
      <input class="form-control" type="text" placeholder="Recipe's Name" v-model="recipe.name">
    </div>
    <div class="form-group">
      <label class="form-label">Chef</label>
      <input class="form-control" type="text" placeholder="Chef's Name" v-model="recipe.chef">
    </div>
    <div class="form-group">
      <label class="form-label">Cooktime</label>
      <select class="form-control" type="text" v-model="recipe.cooktime">
        <option v-for="cookingtime in cookingtimes" :value="cookingtime.value">
          {{ cookingtime.cook }}
        </option>
      </select>
    </div>
    <div class="form-group">
      <label class="form-label">Serves</label>
      <select class="form-control" type="text" v-model="recipe.amount">
        <option v-for="serving in servings" :value="serving.value">
          {{ serving.serves }}
        </option>
      </select>
    </div>
    <div class="form-group">
      <label class="form-label">Description</label>
      <textarea class="form-control" rows="5" placeholder="Recipe Description" v-model="recipe.description"></textarea>
    </div>
    <div class="form-group">
      <label class="form-label">Favorite</label>
      <input type="checkbox" v-model="recipe.favorite">
    </div>

    <button class="btn btn-default" type="button" @click="newIngredient">Add Ingredient</button>
    <div class="form-group" v-for="(ingredient, index) in recipe.ingredients">
      <label class="form-label">Ingredient</label>
      <input type="text" v-model="ingredient.name">
      <a @click="removeIngredient(index)">Remove Ingredient</a>
      <p>Ingredient: {{ ingredient }}</p>
      <p>Index: {{ index }}</p>
    </div>

    <div id="recipe-index-submit-button-container">
      <button type="submit" class="btn btn-default" @click="newRecipe">Submit</button>
    </div>
  </form>
</div>

app/views/api/v1/recipes/index.json.jbuilder

json.array! @recipes, partial: "recipe", as: :recipe

app/views/api/v1/recipes/_recipe.json.jbuilder

json.id recipe.id
json.name recipe.name
json.chef recipe.chef
json.cooktime recipe.cooktime
json.amount recipe.amount
json.description recipe.description
json.favorite recipe.favorite
json.user_id recipe.user_id

json.ingredients do 
  json.array!(recipe.ingredients) do |ingredient|
    json.ingredient_id ingredient.id
    json.ingredient_name ingredient.name
    json.ingredient_recipe_id ingredient.recipe_id
  end
end

app/controllers/api/v1/recipes_controller.rb

class Api::V1::RecipesController < ApplicationController
  def index
    @recipes = Recipe.all
  end

  def create
    @recipe = Recipe.new(recipe_params)
    @recipe.ingredients.build

    if @recipe.save
      render :show
    else
      render json: { errors: @recipe.errors.full_messages }, status: 422
    end
  end

  def show
    @recipe = Recipe.find_by(id: params[:id])
  end

  private

    def recipe_params
      params.require(:recipe).permit(
        :name,
        :chef,
        :cooktime,
        :amount,
        :description,
        :favorite,
        :user_id,
        ingredients:[
          :id,
          :name,
          :recipe_id
        ]
      )
    end
end

app/javascripts/recipes_ctrl.js

$(document).on('ready', function() {
  new Vue({
    el: '#app',
    data: {
      message: "Hello World!",
      recipe: {
        name: '',
        chef: '',
        cooktime: '',
        amount: '',
        description: '',
        favorite: false,
        ingredients: [
          {name: ''},
        ]
      },
      recipes: [],
      errors: {},
      cookingtimes: [
        {cook: "less than 15 minutes", value: "less than 15 minutes"},
        {cook: "15 minutes", value: "15 minutes"},
        {cook: "30 minutes", value: "30 minutes"},
        {cook: "45 minutes", value: "45 minutes"},
        {cook: "1 hour", value: "1 hour"},
        {cook: "1 hour 30 minutes", value: "1 hour 30 minutes"},
        {cook: "2 hours", value: "2 hours"},
        {cook: "2 hours 30 minutes", value: "2 hours 30 minutes"},
        {cook: "3 hours", value: "3 hours"},
        {cook: "3 hours 30 minutes", value: "3 hours 30 minutes"},
        {cook: "4 hours", value: "4 hours"},
        {cook: "more than 4 hours", value: "more than 4 hours"}
      ],
      servings: [
        {serves: "1", value: 1},
        {serves: "2", value: 2},
        {serves: "3", value: 3},
        {serves: "4", value: 4},
        {serves: "5", value: 5},
        {serves: "6", value: 6},
        {serves: "7", value: 7},
        {serves: "8", value: 8},
        {serves: "9", value: 9},
        {serves: "10", value: 10},
        {serves: "11", value: 11},
        {serves: "12", value: 12},
        {serves: "more than 12", value: "more than 12"}
      ]
    },
    methods: {
      newRecipe: function(){
        this.$http.post('/api/v1/recipes.json', this.recipe).then(function(response){
            this.recipes.push(this.recipe);

        }).catch(function(response){
          this.errors = response.data.errors;
        });
        console.log("this.recipe " + this.recipe);
      },
      newIngredient: function(){
        this.recipe.ingredients.push({name:'', recipe_id: ''});
      },
      removeIngredient: function(index){
        console.log("index " + index);
        this.recipe.ingredients.splice(index, 1);
      }
    }
  })
})

这就是终端向我显示的内容。我现在也将我的应用程序 Controller 设置为空 session 。

Processing by Api::V1::RecipesController#create as JSON
  Parameters: {"name"=>"", "chef"=>"", "cooktime"=>"", "amount"=>"", "description"=>"", "favorite"=>false, "ingredients"=>[{"name"=>"test"}, {"recipe_id"=>""], "recipe"=>{"name"=>"", "chef"=>"", "cooktime"=>"", "amount"=>"", "description"=>"", "favorite"=>false}}
Can't verify CSRF token authenticity.
   (4.3ms)  BEGIN
  SQL (5.5ms)  INSERT INTO "recipes" ("name", "chef", "cooktime", "description", "favorite", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["name", ""], ["chef", ""], ["cooktime", ""], ["description", ""], ["favorite", false], ["created_at", 2017-02-05 17:29:34 UTC], ["updated_at", 2017-02-05 17:29:34 UTC]]
  SQL (51.5ms)  INSERT INTO "ingredients" ("recipe_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["recipe_id", 18], ["created_at", 2017-02-05 17:29:34 UTC], ["updated_at", 2017-02-05 17:29:34 UTC]]
   (3.1ms)  COMMIT
  Rendering api/v1/recipes/show.json.jbuilder
  Ingredient Load (0.7ms)  SELECT "ingredients".* FROM "ingredients" WHERE "ingredients"."recipe_id" = $1  [["recipe_id", 18]]
  Rendered api/v1/recipes/_recipe.json.jbuilder (12.2ms)

最佳答案

我认为您在create操作中不需要@recipe.ingredients.build,并且以这种方式保存您需要添加accepts_nested_attributes_for :ingredients食谱

关于javascript - Vue.js 和 Rails 的数据库保存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42055436/

相关文章:

mysql - 如何避免错误 -> 重复输入

javascript - 使用 typescript 作为自定义数据类型在 Angular 中返回 Promise

javascript - 当高度较小时,如何正确显示高脚椅的工具提示?

javascript - 如何将类添加到 svg 路径?

mysql - PG分组错误

javascript - 将项目添加到对象中的数组

javascript - 如何使用 style 属性为 Ext js xtype tabpanel 应用样式?

javascript - DOM - 用节点数组替换节点(有效)

javascript - 如何在 Plotly 中将图例放在顶部而不是底部?

ruby-on-rails - 使用 Rspec stub File.open