- Ruby : 2.2.0
- Rails : 4.1.7
- backbone-on-rails : 1.1.2.0
- jQuery : 1.11.2
rails new backbone_app -d sqlite3 --javascript-engine coffee
cd backbone_app
echo "gem 'backbone-on-rails'" >> Gemfile
bundle install
rails g scaffold task name:string
rake db:migrate
Let's make some data.
10.times { |i| Task.create(name:"title #{i}") }
rm -f app/views/tasks/*
touch app/views/tasks/index.html.erb
rails g backbone:install
mv app/assets/javascripts/backbone_app.js.coffee app/assets/javascripts/todo_list.js.coffee
Change application.js
//= require backbone_app -> //= require todo_list
Change todo_list.js.coffee
window.TodoList =
Models: {}
Collections: {}
Views: {}
Routers: {}
initialize: -> alert 'Hello from Backbone!'
$(document).ready ->
TodoList.initialize()
rails s
- open in browser (Optional)
- Get Inspecter
rails g backbone:scaffold task
app/assets/javascripts/routers/tasks_router.js.coffee
class TodoList.Routers.Tasks extends Backbone.Router
routes:
'': 'index'
index: ->
tasks = new TodoList.Collections.Tasks
new TodoList.Views.TasksIndex collection: tasks
tasks.fetch({reset: true})
app/assets/javascripts/collections/tasks.js.coffee
class TodoList.Collections.Tasks extends Backbone.Collection
url: 'tasks'
model: TodoList.Models.Task
app/assets/javascripts/models/task.js.coffee
class TodoList.Models.Task extends Backbone.Model
app/config/routes.rb
...
root 'tasks#index'
...
app/controllers/tasks_controller.rb
def index
render json: Task.all
end
...
def create
@task = Task.new(task_params)
if @task.save
render json: @task, status: :created
else
render json: @task.errors, status: :unprocessable_entity
end
end
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>BackboneApp</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="app">
<%= yield %>
</div>
</body>
</html>
app/assets/javascripts/views/tasks/tasks_index.js.coffee
class TodoList.Views.TasksIndex extends Backbone.View
el: '#app'
template: JST['tasks/index']
events: ->
'keypress #add-task' : 'createOnEnter'
initialize: ->
@collection.bind 'reset', @render, @
@collection.bind 'add', @addTask, @
render: ->
$(@el).html(@template())
@collection.each (task) ->
view = new TodoList.Views.TaskItem model: task
@$('#tasks').append(view.render().el)
@
app/assets/templates/tasks/index.jst.eco
<div id="tasks">
</div>
app/assets/javascripts/views/tasks/tasks_item.js.coffee
class TodoList.Views.TaskItem extends Backbone.View
template: JST['tasks/item']
render: ->
$(@el).html(@template(task: @model))
@
app/assets/templates/tasks/item.jst.eco
<div><%= @task.get 'name' %></div>
app/assets/javascripts/todo_list.js.coffee
window.TodoList =
Models: {}
Collections: {}
Views: {}
Routers: {}
initialize: ->
new TodoList.Routers.Tasks
Backbone.history.start()
$(document).ready ->
TodoList.initialize()
you can see some task list!!
app/assets/javascripts/views/tasks/tasks_index.js.coffee
class TodoList.Views.TasksIndex extends Backbone.View
el: '#app'
template: JST['tasks/index']
events: ->
'keypress #add-task' : 'createOnEnter'
initialize: ->
@collection.bind 'reset', @render, @
@collection.bind 'add', @addTask, @
render: ->
$(@el).html(@template())
@collection.each (task) ->
view = new TodoList.Views.TaskItem model: task
@$('#tasks').append(view.render().el)
@
app/assets/templates/tasks/index.jst.eco
<label>Add Task:<input id="add-task"/></label>
<div id="tasks">
</div>
app/assets/javascripts/views/tasks/tasks_item.js.coffee
class TodoList.Views.TaskItem extends Backbone.View
template: JST['tasks/item']
events:
'click a.remove-task' : 'removeTask'
initialize: ->
@model.bind 'destroy', @remove, @
render: ->
$(@el).html(@template(task: @model))
@
removeTask: ->
@model.destroy()
app/assets/templates/tasks/item.jst.eco
<div><%= @task.get 'name' %> - <a class="remove-task">remove</a></div>
And Try!
app/assets/javascripts/views/tasks/tasks_index.js.coffee
class TodoList.Views.TasksIndex extends Backbone.View
el: '#app'
template: JST['tasks/index']
events: ->
'keypress #add-task' : 'createOnEnter'
initialize: ->
@collection.bind 'reset', @render, @
@collection.bind 'add', @addTask, @
render: ->
$(@el).html(@template())
footerView = new TodoList.Views.Footer collection: @collection
footerView.render()
@collection.each (task) ->
view = new TodoList.Views.TaskItem model: task
@$('#tasks').append(view.render().el)
@
addTask: (task) ->
view = new TodoList.Views.TaskItem model: task
@$('#tasks').append(view.render().el)
@
createOnEnter: (event)->
return if event.keyCode != 13
@collection.create name: @$('#add-task').val()
@$('#add-task').val('')
app/assets/templates/tasks/index.jst.eco
<label>Add Task:<input id="add-task"/></label>
<div id="tasks">
</div>
<div id="footer"></div>
app/assets/javascripts/views/tasks/footer.js.coffee
class TodoList.Views.Footer extends Backbone.View
el: '#footer'
template: JST['tasks/footer']
initialize: ->
@collection.bind 'add', @updateRemaining, @
@collection.bind 'remove', @updateRemaining, @
render: ->
remaining = @collection.length
$(@el).html(@template({remaining: remaining}))
@
updateRemaining: ->
@$('#task-count').text(@collection.length)
app/assets/templates/tasks/footer.jst.eco
<span>Remaining:
<span id='task-count'><%= @remaining %></span>
</span>
Congratulation! You just finish hands-on!