Search code examples
ruby-on-railsangularjsuser-registration

AngularJS Rails User Sign Up without Devise


I am trying to create a sign up flow with Angular client sending user inputs to the server via the $resource service. The User model on the Rails side has a has_secure_password, password_digest field on the model.

Problem is: (1) Rails sends error to Angular client that "password is missing" even though it is not. (2) Password and confirmation seem to not be getting sent by Angular? (3) Password digest is not getting set, remains "nil".

(1) Rails sends error to Angular client that "password is missing" even though it is not.

 Object { username: "testuser", first_name: "Test", last_name: "User", email: "[email protected]", password: "password5375", password_confirmation: "password5375" } main.js:157
Object { data: Object, status: 422, headers: headersGetter/<(), config: Object, statusText: " " } main.js:163
"password:can't be blank"

(2) Note that the password & confirmation aren't included in the wrapped "user" hash

Started POST "/api/users.json" for 127.0.0.1 at 2014-10-04 19:04:46 -0400
Processing by UsersController#create as JSON
  Parameters: {"username"=>"user3", "first_name"=>"Uss", "last_name"=>"ErThree", "email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "user"=>{"username"=>"user3", "first_name"=>"Uss", "last_name"=>"ErThree", "email"=>"[email protected]"}}
Can't verify CSRF token authenticity
   (0.1ms)  begin transaction
  User Exists (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE "users"."username" = 'user3' LIMIT 1
  SQL (164.1ms)  INSERT INTO "users" ("created_at", "email", "first_name", "last_name", "updated_at", "username") VALUES (?, ?, ?, ?, ?, ?)  [["created_at", Sat, 04 Oct 2014 23:04:46 UTC +00:00], ["email", "[email protected]"], ["first_name", "Uss"], ["last_name", "ErThree"], ["updated_at", Sat, 04 Oct 2014 23:04:46 UTC +00:00], ["username", "user3"]]
   (0.8ms)  commit transaction

(3) From the console, note that the password digest is not getting set.

 User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
 => #<User id: 3, created_at: "2014-10-04 23:04:46", updated_at: "2014-10-04 23:04:46", username: "user3", first_name: "Uss", last_name: "ErThree", email: "[email protected]", password_digest: nil>
1.9.3-p362 :010 > User.last.password_digest
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
 => nil



app.factory('User', function($resource){
  function User() {
    this.service = $resource('/api/users/:id.json', {id: '@id'},
      {
        'update': {method: 'PUT'},
        'show': {method: 'GET', isArray: false}
      }
    );
  }



 User.prototype.all = function() {
    return this.service.query();
  };

  User.prototype.destroy = function(uid) {
    return this.service.remove({id: uid});
  }; 

  User.prototype.create = function(attributes) {
    return this.service.save(attributes);
  };

  User.prototype.update = function(attributes) {
    return this.service.update(attributes);
  };    

  User.prototype.show = function(uid) {
    return this.service.show({id: uid});
  }

  return new User;
});

    app.controller('UsersCreateCtrl', function($scope, User){
  $scope.createUser = function(){
    $scope.user;
    console.log($scope.user);
    var newUser = User.create($scope.user).$promise.then(function(data){
        console.log(data);
        $scope.users.push(newUser);
        $scope.user = {};
    }, function(msg){
        console.log(msg);
        angular.forEach(msg.data.errors, function(type, error){
            console.log(error + ":" + type);
        });
    });
  };
});

<h4>Register</h4>
<div ng-controller="UsersCreateCtrl">
  <form name="form" ng-submit="createUser()" novalidate>
    Name: <input name="username" type="text" ng-model="user.username" placeholder="username"/>
    First Name: <input name="first_name" type="text" ng-model="user.first_name" placeholder="first name" />
    Last Name: <input name="last_name" type="text" ng-model="user.last_name" placeholder="last name" />
    Email: <input name="email" type="text" ng-model="user.email" placeholder="email" />
    Password: <input name="password" type="text" ng-model="user.password" placeholder="password" />
    Confirm Password: <input name="password_confirmation" type="text" ng-model="user.password_confirmation" />
    <input type="submit" value="Register">
  </form>
</div>

EDIT: Rails UsersController Posted

class UsersController < ApplicationController
respond_to :json

protect_from_forgery with: :null_session

def index
    respond_with User.all
end

def create
    respond_with User.create(user_params)
end

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

def show 
    respond_with User.find(params[:id])
end

def update
    respond_with User.find(params[:id]).update_attributes(source_params)
end

private
    def user_params
        params.require(:user).permit(:username, :email, :first_name, :last_name, :password, :password_confirmation)
    end

end


Solution

  • I would guess that your rails controller is not allowing password & password confirmation to be passed to the model due to not permitting them in the strong parameters. Either that or you are not including them in the json user object being posted. Since you are most likely doing User.create!(params[:user]), you need to make sure that you have permitted all the params you are expecting:

    permitted_params = params[:user].permit(:username, :first_name, :last_name, :email, :password, :password_confirmation)
    User.create!(permitted_params)