深度嵌套的rails vue.js(属性的属性)

时间:2018-11-01 17:13:04

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

我通过观看gorails tutorial创建了一个嵌套表单,这很好,我做到了。当我想在其他嵌套模型下创建嵌套模型时,问题开始了。我有Survey模型,它是主要模型。然后,我添加了Question模型并使用vue.js制作了表格。因此,我在问题中添加了Choice模型(您可以在测量控制器参数中注意到)第一个问题是;我不知道如何在vue.js控件中定义/实现。(hello_vue.js)第二个要点是:如何在new.html中创建表单元素

这是我的survey.rb模型:

class Survey < ApplicationRecord
    has_many :questions, dependent: :destroy
    accepts_nested_attributes_for :questions, allow_destroy: true
    belongs_to :user
end

and surveys_controller.rb

class SurveysController < ApplicationController
  before_action :set_survey, only: [:show, :edit, :update, :destroy]


    def survey_params
      params.require(:survey).permit(:user_id, :name, questions_attributes:[:id,:survey_id, :title, :qtype, :_destroy, choices_attributes:[:id,:question, :ctext]])
    end
end

这是Survey的嵌套模型:question.rb:

class Question < ApplicationRecord
    enum qtype: [:multiple_choice, :check_boxes, :short_answer]
  belongs_to :survey
  has_many :choices
  accepts_nested_attributes_for :choices, allow_destroy: true
end

最后的vue.js文件:

 import TurbolinksAdapter from 'vue-turbolinks'
 import Vue from 'vue/dist/vue.esm'
 import VueResource from 'vue-resource'

Vue.use(VueResource)
Vue.use(TurbolinksAdapter)

Vue.component('app', App)
 document.addEventListener('turbolinks:load', () => {
    Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
      var element = document.getElementById("survey-form")


if (element != null){
    var survey = JSON.parse(element.dataset.survey)
    var questions_attributes = JSON.parse(element.dataset.questionsAttributes)
    var choices_attributes = JSON.parse(element.dataset.choicesAttributes)
    questions_attributes.forEach(function(question) { question._destroy = null })
    survey.questions_attributes = questions_attributes

    var app = new Vue({

    el: element,
    //mixins: [TurbolinksAdapter],  
    data: function(){
        return { survey: survey }

    },

    methods:{
        addQuestion: function(){

            this.survey.questions_attributes.push({
                id: null,
                title:"",
                qtype:"",
                _destroy: null


            })
        },
       removeQuestion: function(index) {
          var question = this.survey.questions_attributes[index]

          if (question.id == null) {
            this.survey.questions_attributes.splice(index, 1)
          } else {
            this.survey.questions_attributes[index]._destroy = "1"
          }
        },
        undoRemove: function(index) {
          this.survey.questions_attributes[index]._destroy = null
        },

                saveSurvey: function() {
          // Create a new survey
          if (this.survey.id == null) {
            this.$http.post('/surveys', { survey: this.survey }).then(response => {
              Turbolinks.visit(`/surveys/${response.body.id}`)
            }, response => {
              console.log(response)
            })




          // Edit an existing survey
          } else {
            this.$http.put(`/surveys/${this.survey.id}`, { survey: this.survey }).then(response => {
              Turbolinks.visit(`/surveys/${response.body.id}`)
            }, response => {
              console.log(response)
            })
          }
        },


        existingSurvey: function() {
          return this.survey.id != null
        }

    }   
   })
    }


 })

_form.html.erb

<%= content_tag :div,
    id: "survey-form",
    data: {
      survey: survey.to_json(except: [:created_at, :updated_at]),
      questions_attributes: survey.questions.to_json,

    } do %>

<label>Survey Name</label>
<input qtype="text" v-model="survey.name">

<h4>Questions</h4>
<div v-for="(question, index) in survey.questions_attributes">
    <div v-if="question._destroy == '1'">
      {{ question.title }} will be removed. <button v-on:click="undoRemove(index)">Undo</button>
    </div>
    <div v-else>
      <label>Question</label>

      <input qtype="text" v-model="question.title" />

     <label>Qestion qtype</label>
  <select v-model="question.qtype">
  <option v-for="qtype in <%= Question.qtypes.keys.to_json %>"
    :value=qtype>
    {{ qtype }}
  </option>
</select>


      <button v-on:click="removeQuestion(index)">Remove</button>
    </div>

    <hr />
  </div>

  <button v-on:click="addQuestion">Add Question</button>

<br>

<button v-on:click="saveSurvey" >Save Survey</button>


    <% end %>

1 个答案:

答案 0 :(得分:1)

我遵循了相同的教程,并开始使用带有更复杂的嵌套属性的JSON.parse遇到问题。尝试使用Jbuilder构建JSON对象,并查看gon gem以将Rails变量传递到Javascript中。使用Rails所需的嵌套命名,查询数据库并将结果传递到Javascript文件将更加容易。例如...

survey = @survey

json.id survey.id

json.survey do
  json.(survey, :user_id, :name)  
  json.questions_attributes survey.questions do |question|
    json.(question, :id, :title, :qtype, :_destroy)
    json.choices_attributes question.choices do |choice|
      json.(choice, :id, :ctext)
    end
  end
end

它允许您执行类似...

var survey = gon.survey

而不是...

var survey = JSON.parse(element.dataset.survey)

您可以通过控制器操作传递gon.jbuilder,并准备好定义的JSON对象并在Vue中可用。