Angular表单POST转到错误的操作URL

时间:2015-07-14 13:18:42

标签: javascript ruby-on-rails angularjs

一个rails newbie,我在使用Angular JS提交表单时遇到了问题。我已在url字段中指定/联系$http,POST请求转到root

在我的导轨routes.rb我有

Rails.application.routes.draw do
  get 'home/index'
  post 'home/contact' => "home#contact"
  root 'home#index' 
end

控制器非常基本

class HomeController < ApplicationController
  def index

  end

  def contact
    @captcha = params[:g-recpatcha-response]
    @contact = ContactRequest.new(params[...])
    ....
  end
end

更新

AngularJS包含在angular-rails gem中,并使用require

中的application.js属性进行了归档
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require jquery.easing.1.3.min
//= require jquery.sticky
//= require jquery.stellar.min
//= require wow.min
//= require custom
//= require contact_me.js
//= require jqBootstrapValidation.js
//= require angular
//= require_tree ./angular
//= require main.js

application.html.erb的HTML代码段如下

<!DOCTYPE html>
<html>
<head>
  <title>Etheron</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'https://www.google.com/recaptcha/api.js', :async => "", :defer => "" %>
  <%= csrf_meta_tags %>
</head>
<body>

<%= render "layouts/header" %>
<%= yield %>
<%= render "layouts/footer" %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= debug(params) if Rails.env.development? %>
</body>
</html>

,表单包含在index.html.erb

<div ng-app="etherOn" class="form-contact">
            <div class="required">
                <p>( <span>*</span> fields are required )</p>
            </div>

           <form ng-controller="formController" ng-submit="contactRequest()"  name="sentMessage" id="contactForm" novalidate>
                <div class="row">
                    <div class="col-md-6">
                        <div class="row control-group">
                            <div class="form-group col-xs-12 controls" ng-class="{ 'has-error' : formData.name.$invalid && !formData.name.$pristine }">
                                <label>Name<span>*</span></label>
                                <input type="text" class="form-control" placeholder="Name" id="name" required ng-model="formData.name">
                                <!-- <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p> -->
                            </div>
                        </div>

                    </div>

                    <div class="col-md-6">
                        <div class="row control-group">
                            <div class="form-group col-xs-12 controls" ng-class="{ 'has-error' : formData.email.$invalid && !formData.email.$pristine }">
                                <label>Email Address<span>*</span></label>
                                <input type="email" class="form-control" placeholder="Email Address" id="email" required ng-model="formData.email">
                                <!-- <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">You name is required.</p> -->
                            </div>
                        </div> 
                    </div>
                </div>
                <div class="row control-group">
                    <div class="form-group col-xs-12  controls" ng-class="{ 'has-error' : formData.phone.$invalid && !formData.phone.$pristine}" >
                        <label>Phone Number<span>*</span></label>
                        <input type="tel" class="form-control" placeholder="Phone Number" id="phone" required ng-model="formData.phone">
                        <!-- <p ng-show="userForm.phone.$invalid && !userForm.phone.$pristine" class="help-block">You name is required.</p> -->
                    </div>
                </div>
                <div class="row control-group">
                    <div class="form-group col-xs-12 controls" ng-class="{ 'has-error' : formData.message.$invalid && !formData.message.$pristine}" >
                        <label>Message<span>*</span></label>
                        <textarea rows="5" class="form-control" placeholder="Message" id="message" required ng-model="formData.message"></textarea>
                        <!-- <p ng-show="userForm.message.$invalid && !userForm.message.$pristine" class="help-block">You name is required.</p> -->
                    </div>
                </div>
                <div class="row control-group">
                    <div class="form-group col-xs-12 controls">
                        <div class="g-recaptcha" data-sitekey="6Lf2xAkTAAAAAOpJvpHn10HDPBTGP55ROzl01nIP"> </div>
                        <!-- -->
                    </div>
                </div>
                <br>
                <div id="success"></div>
                <div class="row">
                    <div class="form-group col-xs-12">
                        <button type="submit" class="btn btn-theme-bg btn-lg">Send Message</button>
                    </div>
                </div>
            </form>

        </div><!--contact form-->

javascript代码位于main.js文件中,用于表单提交

var app = angular.module("etherOn", []);

app.controller("formController", function($http, $scope) {
        $scope.formData = {};

        console.log("submit form");

        $scope.contactRequest = function() {
            if($scope.formData.g-recaptcha-response === ""){ //if string is empty
                // TODO: use bootstrap sweet modals here
                alert("Please resolve the captcha and submit!")
            }else{
                var post_data = $.param($scope.formData);
                $http.post({
                    method: 'POST',
                    url: 'home/contact',
                    data: post_data,
                    headers : { "X-CSRF-Token" : $('meta[name="csrf-token"]').attr('content'),'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }
                }).success(function(response){
                    console.log(response);
                    if(response.error === 0){
                        alert("Successfully verified and signed up the user");
                    }else{
                        alert("User verification failed");
                    }
                })
                .error(function(error){

                })
            }               
        }
    });

问题是AngularJS表单提交代码永远不会被调用,从不同的tutuments尝试了很多片段,没有帮助。有一些详细示例,但它们都基于ActiveRecord,我不想在这里使用,因为我所做的就是使用sendgrid生成一个电子邮件,表单已提交。

2 个答案:

答案 0 :(得分:0)

我想也许你错过了表单提交网址和$ http网址。

表单标记提交网址与$ http网址不同。

首先,您的表单标记没有操作。所以默认操作网址是“/”(现在是页面)

  1. 提交表单时,执行ng-submit =“”。
  2. ng-submit block $ http已执行。 ($ http是 async block
  3. ng-submit阻止结束后,表单将提交!
  4. 因为表单操作url“/”,表单提交为“/”

    我认为你错过了关于上述2的更多观点。

    也许偶数2号进程($ http post例程)不起作用

    错误点

    Rails有检查例程csrf-token。因此,当您发布操作时,操作跳过before_filter:verify_authenticity_token(A)或在angularjs中,将csrf-token添加到$ http标头。 (B)

    #(A)
    skip_before_filter :verify_authenticity_token
    
    #(B)
    $http({
            method  : 'POST',
            url     : '/contact',
            data    : $.param($scope.formData),  // pass in data as strings
            headers : { "X-CSRF-Token" : $('meta[name="csrf-token"]').attr('content') }
        })
    // $('meta[name="csrf-token"]') tag is generated by layout <%= csrf_meta_tags %>
    

答案 1 :(得分:0)

有多个问题导致这种情况,主要是因为我混淆了事情,我添加了一个角度重新接收模块,它没有正确加载并且执行了脚本的其余部分失败,删除了它,修复了角形状然后重新 - 启用验证码以使工作正常。谢谢你们的帮助!

这是结构,现在可以使用

application.js

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require jquery.easing.1.3.min
//= require jquery.sticky
//= require jquery.stellar.min
//= require wow.min
//= require custom
//= require angular
//= require angular-recaptcha.min.js
//= require main.js

application.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>Etheron</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'https://www.google.com/recaptcha/api.js?render=explicit&onload=vcRecaptchaApiLoaded', :async => "", :defer => "", 
    :type =>"text/javascript" %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true , :type =>"text/javascript" %>
  <%= csrf_meta_tags %>
</head>
<body ng-app="etherOn">

<%= render "layouts/header" %>
<%= yield %>
<%= render "layouts/footer" %>
<%= debug(params) if Rails.env.development? %>
</body>
</html>

包含在index.html.erb

中的表单
<div class="form-contact" ng-controller="formController">
            <div class="required">
                <p>( <span>*</span> fields are required )</p>
            </div>
            <div id="success" class="alert alert-success" ng-show="messages" ng-bind="messages"></div>
            <form name="sentMessage" role="form" novalidate>
                <div class="row">
                    <div class="col-md-6">
                        <div class="row control-group">
                            <div class="form-group col-xs-12 controls">
                                <label>Name<span>*</span></label>
                                <span class="label label-danger" ng-show="submitted && sentMessage.name.$error.required">Required!</span>
                                <input type="text" class="form-control" placeholder="Name" name="name" required ng-model="contact.name">
                            </div>
                        </div>

                    </div>

                    <div class="col-md-6">
                        <div class="row control-group">
                            <div class="form-group col-xs-12 controls">
                                <label>Email Address<span>*</span></label>
                                <span class="label label-danger" ng-show="submitted && sentMessage.email.$error.required">Required!</span>
                                <input type="email" class="form-control" placeholder="Email Address" name="email" required ng-model="contact.email">
                            </div>
                        </div> 
                    </div>
                </div>
                <div class="row control-group">
                    <div class="form-group col-xs-12  controls">
                        <label>Phone Number<span>*</span></label>
                        <span class="label label-danger" ng-show="submitted && sentMessage.phone.$error.required">Required!</span>
                        <input type="tel" class="form-control" placeholder="Phone Number" name="phone" required ng-model="contact.phone">
                    </div>
                </div>
                <div class="row control-group">
                    <div class="form-group col-xs-12 controls">
                        <label>Message<span>*</span></label>
                        <span class="label label-danger" ng-show="submitted && sentMessage.message.$error.required">Required!</span>
                        <textarea rows="5" class="form-control" placeholder="Message" name="message" required ng-model="contact.message"></textarea>
                    </div>
                </div>

                <div class="row control-group">
                    <div class="form-group col-xs-12 controls">
                        <label>Verify<span>*</span></label>
                        <span class="label label-danger" ng-show="submitted && response === null">Required!</span>
                        <div vc-recaptcha theme="'light'" 
                        key="model.key" 
                        on-create="setWidgetId(widgetId)" 
                        on-success="setResponse(response)"></div>
                    </div>
                </div>
                <br>
                <div class="row">
                    <div class="form-group col-xs-12">
                        <button type="submit" class="btn btn-theme-bg btn-lg" ng-click="contactRequest(sentMessage)">Send Message</button>
                    </div>
                </div>
            </form>

        </div><!--contact form-->

和脚本

angular.module("etherOn", ['vcRecaptcha'])
.config([
    "$httpProvider", function($httpProvider) {
        $httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
    }
])
.controller("formController",["vcRecaptchaService","$http","$scope", "$timeout", function(vcRecaptchaService,$http, $scope, $timeout) {

        $scope.contact = {};
        $scope.submitted = false;
        $scope.response = null;
        $scope.widgetId = null;
        $scope.model = {
            key: "6Lf2xAkTAAAAAOpJvpHn10HDPBTGP55ROzl01nIP"
        };

        $scope.setResponse = function (response) {
            $scope.response = response;
        };

        $scope.setWidgetId = function (widgetId) {
            $scope.widgetId = widgetId;
        };

        $scope.contactRequest = function(form) {

            // Trigger validation flag.
            $scope.submitted = true;

            // If form is invalid, return and let AngularJS show validation errors.
            if (form.$invalid) {
                return;
            }else{

                var post_data = {  //prepare payload for request
                    'name':$scope.contact.name,
                    'email':$scope.contact.email,
                    'phone':$scope.contact.phone,
                    'message':$scope.contact.message,
                    'captcha':$scope.response  //send g-captcah-reponse to our server
                }

                console.log(post_data);

                $http.post(
                    'home/contact',post_data
                ).success(function(response){
                    console.log(response);
                    if(response.error === 0){
                        $scope.messages = "Thanks!" + $scope.name + "for your request! We will get back to you shortly"
                    }else{
                        $scope.messages = "We are sorry but your request was not processed, please try again."
                    }
                })
                .error(function(error){
                    $scope.messages = "We are sorry but your request was not processed, please try again."
                })
                .finally(function() {
                // Hide status messages after three seconds.
                    $timeout(function() {
                        $scope.messages = null;
                    },  5000);
                    vcRecaptchaService.reload($scope.widgetId);
                });
            }   
        }
    }]);