简体   繁体   中英

AngularJS + Rails Post Request

I'm trying to learn to use AngularJS as the front-end framework in Rails applications. So far, I'm able to display a list of resources from the Rails app in view using Angular, and I can send a delete request with Angular. However, I'm having difficulty creating new resources. If someone could tell me what I might be doing wrong, that would be really appreciated.

edit I've made a bit of progresses. Looking at heroku logs, I realized I had made a silly mistake and forgot to account for the authenticity token. Now I'm getting the error: ArgumentError (When assigning attributes, you must pass a hash as an argument.):

assets/javascript/angular_app.js

var app = angular.module('shop', ['ngResource']);

app.factory('models', ['$resource', function($resource){
    var orders_model = $resource("/orders/:id.json", {id: "@id"});
    var products_model = $resource("/products/:id.json", {id: "@id"});
    var users_model = $resource("/users/:id.json", {id: "@id"});
    var x = {
        orders: orders_model,
        products: products_model,
        users: users_model
    };
    return x;
}]);

app.controller('OrdersCtrl', ['$scope', 'models', function($scope, models){
    $scope.orders = models.orders.query();
    $scope.products = models.products.query();
    $scope.users = models.users.query();
    $scope.addOrder = function(){
        order = models.orders.save($scope.newOrder, function(){
            recent_order = models.orders.get({id: order.id});
            $scope.orders.push(recent_order);
            $scope.newOrder = '';
        });
    }
    $scope.deleteOrder = function(order){
        models.orders.delete(order);
        $scope.orders.splice($scope.orders.indexOf(order), 1);
    }
}]);

orders_controller.rb

class OrdersController < ApplicationController        
    protect_from_forgery
    skip_before_action :verify_authenticity_token, if: :json_request?ion
    respond_to :json, :html

    def index
        @orders = Order.all.to_json(:include => [{:product => {:only => :name}},
                                                 {:user => {:only => :email}}])
        respond_with @orders
    end

    def show
        @order = Order.find(params[:id]).to_json(:include => [{:product => {:only => :name}},
                                                              {:user => {:only => :email}}])
        respond_with @order
    end

    def new
    end

    def create
        @order = Order.create(:order_params)
        @order.product = Product.find(params[:product_id])
        @order.user = User.find(params[:user_id])  

        OrderMailer.order_confirmation(@order.product, @order.user.email, @order.user.first_name)

        respond_with @order
    end

    def destroy
        respond_with Order.destroy(params[:id])
    end

    protected

    def json_request?
        request.format.json?
    end

    private

    def order_params
        params.require(:order).permit(:product_id, :user_id, :total)
    end
end

orders/index.html.erb

<div ng-controller="OrdersCtrl">
    <table class="table table-hover">
        <thead>
            <td>Order ID</td>
            <td>Total</td>
            <td>Product</td>
            <td></td>
        </thead>
        <tr>
            <form ng-submit="addOrder()">
                <td>
                    <span class="form-control" disabled>
                        <%= Order.last.id + 1 %>
                    </span>
                </td>
                <td>
                    <input type="number" step="0.01" class="form-control" ng-model="newOrder.total">
                </td>
                <td>
                    <select ng-model="newOrder.product_id" class="form-control">
                        <option value="" disabled selected>Select a product</option>
                        <option ng-repeat="product in products" value="{{product.id}}">{{product.name}}</option>
                    </select>
                </td>
                <td>
                    <select ng-model="newOrder.user_id" class="form-control">
                        <option value="" disabled selected>Select a user</option>
                        <option ng-repeat="user in users" value="{{user.id}}">{{user.id}}</option>
                    </select>
                </td>
                <td>
                    <input type="submit" value="+" class="btn btn-success">
                </td>
            </form>
        </tr>
        <tr ng-repeat="order in orders | orderBy: '-id':reverse">
            <td>
                {{order.id}}
            </td>
            <td>
                <strong>{{order.total | currency}}</strong>
            </td>
            <td>
                {{order.product.name}}
            </td>
            <td>
                {{order.user.email}}
            </td>
            <td>
                <button ng-click="deleteOrder(order)" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
            </td>
        </tr>
    </table>
</div>

Try this instead

app.factory('Order', ['$resource', function($resource) {
  return $resource('/api/orders/:id.json', null,
    {
        'update': { method:'PATCH' }
    });
}]);

and then something like this in Angular.

app.controller('OrdersCtrl', ['$scope', 'models' 'Order', function($scope, models, Order){
...

   $scope.addOrder = function(){
        var order = new Order($scope.newOrder);
        Order.save(order, function(res){
            $scope.orders.push(res);
            $scope.newOrder = '';
        });
    }
 })

Your newOrder object isn't an instance of ngResource so when you are calling save on it, that doesn't work. Assuming you are having some console errors in your browser as well along those lines.

You also need the update: patch custom method on ngResource because Rails looks for updates as patch and not put or else you will be asking that question after you figure out this one :).

Aha, I finally have it working. I made a silly typo:

In the create action of the orders controller

   @order = Order.create(:order_params)

should be

   @order = Order.create(order_params)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM