[Vue.js] 結合Rails建立簡易CRUD
1. 首先先建立一個vue101的專案
rails new vue101 -T
2. 加入vue套件 (這步驟可以改用現成的gem vuejs-rails)
-
把vue.js、vue-resource.js放進
/vendor/assets/javascript/
中 (vue-resource是Vue處理JSONP web requests的plugin,這邊的範例需要用到) -
把他們require進來
// [path] app/assets/javascript/application.js
//= require vue
//= require vue-resource
3. 拿掉turbolinks這個gem (會跟vue衝到)
- 其實只要從首頁拿掉他的載入參數即可
<%= javascript_include_tag 'application' %>
- 並且要把這行移至
</body>
前 (放在head是無法work的)
4. 參考vue官網的todolist範例,這邊也使用rails scaffold建立一個todolist來對照
-
vue官網的Todo範例 點我看範例
-
建立一個Todo的scaffold,有一個text的欄位
rails g scaffold Todo text:string
rake db:migrate
-方便測試,這邊把route加到首頁
# [path] route.rb
root 'todo#index'
resources :todos
5. 改用js取代coffee
- 因為用js比較方便,所以…就換掉吧 (可以參考這篇)
# [path] config/applicatioin.rb
config.generators.javascript_engine :js
6. 把Vue範例部分放進來
- 把網頁部分放到post的index.html.erb下方
<!-- [path] app/views/todos/index.html.erb -->
(...上略)
<hr>
<div id="app">
<input v-model="newTodo" v-on:keyup.enter="addTodo">
<ul>
<li v-for="todo in todos">
<span></span>
<button v-on:click="removeTodo($index)">X</button>
</li>
</ul>
</div>
- 把js部分放到對應的post.js
// [path] app/assets/javascripts/todos.js
new Vue({
el: '#app',
data: {
newTodo: '',
todos: [
{ text: 'Add some todos' }
]
},
methods: {
addTodo: function () {
var text = this.newTodo.trim()
if (text) {
this.todos.push({ text: text })
this.newTodo = ''
}
},
removeTodo: function (index) {
this.todos.splice(index, 1)
}
}
})
- 可以先確認一下Vue部分有沒有work
7.CRUD實作 - 前置
- 這邊需要做一個前置動作,因為rails會有csrf taken的機制,因此再送出表單時需要特別在header加入token,這邊直接統一加在application.js中,之後就不用分別在每次的request加入了
// [path] app/assets/javascripts/application.js
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name="csrf-token"]').attr('content');
8.CRUD實作 - 清單頁
- 先新增一個抓todo清單的method: fetchTodos(隨便命名的)
- 並且再插入一個created 執行fetchTodos (至於為什麼是created,可以參考官網說明instance lifecycle(https://vuejs.org/guide/instance.html#Instance-Lifecycle))
// [path] app/assets/javascripts/todos.js
new Vue({
(...略)
created: function() {
this.fetchTodos();
},
methods: {
fetchTodos: function(){
this.$http.get('posts').then(function(response){
this.todos = response.data;
});
},
(...略)
- 可以看到
$http.get('todos')
,表示用get
方式送至http://localhost:3000/todos/
並回傳結果到response
,執行function(response){}
中的項目 - $http用法可以參考vue-resource的說明
- 所以現在我們知道,要到todo#index中,寫回傳js會做的事情,這邊將
@todos
以json方式丟出 (其實不寫也可以他會自動腦補@todo是要回傳的值,如果今天要回傳@list就一定要寫)
# [path] app/controllers/todos_controller.rb
def index
@todos = Todo.all
respond_to do |format|
format.html
format.json { render json: @todos }
end
end
- 因此在response.data中,就可以收到
9.CRUD實作 - 新增
- 這邊將新增做調整,加入ajax回寫
// [path] app/assets/javascripts/todos.js
(...略)
addTodo: function () {
var text = this.newTodo.trim()
if (text) {
this.$http.post('posts', {title: title}).then(function(response){
this.todos.push({ title: title, id: response.data.id })
this.newTodo = ''
});
}
},
(...略)
10.CRUD實作 - 刪除
- 刪除比較麻煩一點,因為後端要對應id,但是前端splice是要看index,因此我調整為兩個參數傳入
// [path] app/assets/javascripts/todos.js
(...略)
removeTodo: function (index, todo) {
this.$http.delete('todos/'+todo.id).then(function(response){
this.todos.splice(index, 1)
});
}
(...略)
- 因為改兩個參數傳入,template也要同步調整
<!-- [path] app/views/todos/index.html.erb -->
<li v-for="todo in todos">
<span></span>
<button v-on:click="removeTodo($index, todo)">X</button>
</li>
11.CRUD實作 - 編輯
- 接下來就開始亂寫了
直接看github吧 Vue101
留言