I am trying to integrate AngularJS into my Mongoid-powered Rails application. In particular, I want the get the basic CRUD operations to work.
1) Saving a book works!
2) Editing fails: Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array
3) Deleting fails: DELETE http://localhost:3000/books 404 (Not Found)
I suspect that these errors are Mongoid specific as I have tried the exact same code with SQlite and ActiveRecord without any issues. The problems arise with Mongoid and in particular for CRUD operations that are applied on a single record/document. Any suggestions on what's wrong?
books_ctrl.js.coffee
myApp.factory "Book", ($resource) ->
$resource("/books/:id", {id: "@id"}, {update: {method: "PUT"}})
myApp.controller "BooksCtrl", ($scope, Book) ->
$scope.getBooks = () ->
Book.query().$promise.then (books) ->
$scope.books = books
$scope.edit = (book) ->
$scope.book = Book.get({id: book.id})
$scope.delete = (book) ->
book.$delete ->
$scope.getBooks()
$scope.save = () ->
if $scope.book.id?
Book.update($scope.book).$promise.then ->
$scope.getBooks()
else
Book.save($scope.book).$promise.then ->
$scope.getBooks()
$scope.book = {}
books_controller.rb
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :destroy]
# GET /books
def index
@books = Book.all
respond_to do |format|
format.html {}
format.json {render json: @books, root: false}
end
end
# GET /books/1
def show
respond_to do |format|
format.html {}
format.json {render json: @book, root: false}
end
end
# GET /books/new
def new
@book = Book.new
end
# GET /books/1/edit
def edit
end
# POST /books
def create
@book = Book.new(book_params)
respond_to do |format|
if @book.save
format.html {render redirect_to @book, notice: 'Book was successfully created.'}
format.json {render json: @book}
else
format.html {render action: 'new'}
format.json {render json: @book.errors, status: :unprocessable_entity}
end
end
end
# PATCH/PUT /books/1
def update
respond_to do |format|
if @book.update(book_params)
format.html {redirect_to @book, notice: 'Book was successfully updated.'}
format.json {render json: @book}
else
format.html {render action: 'edit'}
format.json {render json: @book.errors, status: :unprocessable_entity}
end
end
end
# DELETE /books/1
def destroy
@book.destroy
respond_to do |format|
format.html {redirect_to books_url, notice: 'Book was successfully destroyed.'}
format.json {render json: {message: "Book was deleted."}}
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def book_params
params.require(:book).permit(:title, :author)
end
end
books\index.html.erb
<div ng-app="myApp" ng-controller="BooksCtrl" ng-init="getBooks()">
<div class="container">
<div class="row">
<div class="span12">
<form ng-submit="save()">
<div class="form-group">
<label>Author</label>
<input type="text" class="form-control span12" ng-model="book.author"/>
</div>
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control span12" ng-model="book.title"/>
</div>
<button class="btn btn-success">
Save
</button>
</form>
<hr />
<ul>
<li ng-repeat="book in books">
<div class="btn-group">
<div class="btn btn-mini btn-danger" ng-click="delete(book)">
<i class="icon-trash"></i>
</div>
<div class="btn btn-mini btn-default" ng-click="edit(book)">
<i class="icon-edit"></i>
</div>
</div>
{{$index + 1}} {{book.title}} by {{book.author }}
</li>
</ul>
</div>
</div>
</div>
</div>