CODE:
Rails controller:
def destroy
respond_with Post.find(params[:id]).destroy
end
Angular factory:
.factory('posts', [
'$http',
function($http) {
var o = {
posts: []
};
o.destroy = function(post) {
return $http.delete('posts.json', post).success(function(data) {
o.posts.splice(o.posts.indexOf(data), 1);
});
};
return o;
}
]);
Part of a main module:
angular.module('flapperNews', ['ui.router', 'templates', 'Devise'])
.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home/_home.html',
controller: 'MainCtrl',
resolve: {
postPromise: ['posts', function(posts) {
return posts.getAll();
}]
}
})
}
]);
mainCtrl.js:
angular.module('flapperNews')
.controller('MainCtrl', [
'$scope',
'posts',
function($scope, posts) {
$scope.posts = posts.posts;
...
$scope.destroy = function(post) {
posts.destroy(post);
};
}
]);
PROBLEM:
When trying to click on delete button ng-click="destroy(post)" - it doesn't work and gives me the error:
DELETE http://localhost:3000/posts.json 404 (Not Found)
The interesting part is when I change my $http.delete to $http.post - it works, but on refresh I have 2 same posts(obviously).
I am a newbie in both angular and rails, so I would really appreciate your help.
Rake routes:
Make sure you have resources :posts in your rails routes file.
Okay, I got this.
The problem was in this row: return $http.delete('posts.json', post). Need to change this to
return $http.delete('/posts/' + post.id + '.json'), as rake routes says it should be.
Related
I am trying to authenticate into devise via angular. On loading localhost, I see a POST 401 error. This issue seems to be with some devise setting, as my X-CSRF-TOKEN is being passed, but my POST requests aren't accepted.
I am able to register a user successfully, and immediately log in to that user (register also logs user in). I am then able to log out.
Here is the issue: I cannot log in to that user again.
My angular app is inside rails, so the two aren't disconnected.
What do I do? Here are relevant files:
app.js
var myApp = angular.module('myApp', ['templates','ui.router','ui.bootstrap', 'Devise']);
myApp.config([
'$httpProvider', function($httpProvider) {
return $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
}
]);
myApp.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
/**
* Routes and States
*/
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html',
controller: 'HomeCtrl'
})
.state('login', {
url: '/login',
templateUrl: 'login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function (){
$state.go('home');
})
}]
})
.state('register', {
url: '/register',
templateUrl: 'register.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'Auth', function($state, Auth) {
Auth.currentUser().then(function (){
$state.go('home');
})
}]
});
// default fall back route
$urlRouterProvider.otherwise('/');
// enable HTML5 Mode for SEO
//$locationProvider.html5Mode(true);
});
myApp.run(function() {
return console.log('angular app running');
});
authCtrl.js
angular.module('myApp')
.controller('AuthCtrl', [
'$scope',
'$state',
'Auth',
function($scope, $state, Auth){
$scope.login = function() {
Auth.login($scope.user).then(function(){
$state.go('home');
});
};
$scope.register = function() {
Auth.register($scope.user).then(function(){
$state.go('home');
});
};
}]);
navCtrl.js
angular.module('myApp')
.controller('NavCtrl', [
'$scope',
'Auth',
function($scope, Auth){
$scope.signedIn = Auth.isAuthenticated;
$scope.logout = Auth.logout;
Auth.currentUser().then(function (user){
$scope.user = user;
});
$scope.$on('devise:new-registration', function (e, user){
$scope.user = user;
});
$scope.$on('devise:login', function (e, user){
$scope.user = user;
});
$scope.$on('devise:logout', function (e, user){
$scope.user = {};
});
}]);
applicaton_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
respond_to :json
def index
end
end
I have Devise gem installed, and using angular, angular-ui, angular-devise in Bowerfile
It looks like changing :exception to :null_session worked.. Why is this?
I'm trying to add authorization functionality to my app, sow for example when I want to go to /admin/posts/create it will redirect me to /login if I'm not already logged in.
My angular module
angular.module('flapperNews', ['ui.router', 'templates', 'ngResource', 'formly', 'formlyBootstrap', 'ngMessages', 'Devise'])
I'm using this service
angular.module('flapperNews')
.factory('authorization', [
'$state',
'Auth',
'$location',
function($state, Auth, $location) {
return {
authorize: function() {
var isAuthenticated = Auth.isAuthenticated();
if (isAuthenticated === false) {
$state.go('login');
}
}
};
}
]);
These are my routes
$stateProvider.state('home', {
url: '/',
controller: 'PostsCtrl',
templateUrl: 'posts/_posts.html'
});
$stateProvider.state('admin', {
abstract: true,
resolve: {
authorize: ['authorization', function(authorization) {
return authorization.authorize();
}]
},
template: '<div ui-view />'
});
$stateProvider.state('postsCreate', {
parent: 'admin',
url: '/admin/posts/create',
controller: 'PostsCtrl as vm',
templateUrl: 'posts/create.html'
});
Through this link I'm trying to access route where I shouldn't be able to get
<a ui-sref="postsCreate" class="btn btn-primary">Create a post</a>
I don't get any errors and I end up in section which I should be able to access.
I'm using rails with devise, and angular with ng-file-upload.
I have two problems. first as soon as I go to the root of the website a POST request is executed to try to sign in the user with results in a 500 status code response.
It says it can't find the users_url, which makes sense because I don't have in my routes, what is weird is that request being fired.
Also using the ng-file-upload, when I load a dialog to upload a file, the dialog loads and it sends the request to upload the file directly. With no wait in between.
Why is this happening?
THis are the differents files being excuted in all this actions:
app.coffee
app = angular.module("inkorporated", ['ui.router', 'templates', 'rails', 'Devise', 'ngFileUpload', 'ngDialog'])
.config(['$stateProvider','$urlRouterProvider',
($stateProvider, $urlRouterProvider)->
$stateProvider
.state('home', {
url: '/home'
templateUrl: 'home/_home.html'
controller: 'SearchCtrl'
})
.state('login', {
url: '/login'
templateUrl: 'auth/_login.html'
controller: 'AuthCtrl'
onEnter: ['$state', 'Auth', ($state, Auth)->
Auth.currentUser().then ->
$state.go('home')
return
return
]
})
.state('register', {
url: '/register'
templateUrl: 'auth/_register.html'
controller: 'AuthCtrl'
onEnter: ['$state', 'Auth', ($state, Auth)->
Auth.currentUser().then ->
$state.go('home')
return
return
]
})
.state('user', {
url: '/user/{id}'
templateUrl: 'users/_user.html'
controller: 'UserCtrl'
})
$urlRouterProvider.otherwise('home')
return
])
navCtrl.coffee
angular.module("inkorporated").controller('NavCtrl', ['$scope', '$state', 'Auth',
($scope, $state, Auth)->
$scope.config = {
headers: {
'X-CSRF-TOKEN': $('meta[name=csrf-token]').attr("content")
}
}
$scope.signedIn = Auth.isAuthenticated
$scope.logout = Auth.logout
Auth.currentUser().then(
(user)->
if !!user.email
$scope.user = user
else
$scope.user = {}
return
)
$scope.$on('devise:new-registration',
(e, user)->
$scope.user = user
return
)
$scope.$on('devise:login',
(e, user)->
if !!user.email
$scope.user = user
else
$scope.user = {}
return
)
$scope.$on('devise:logout',
(e, user)->
$scope.user = {}
return
)
return
])
avatarCtrl.coffee
angular.module("inkorporated").controller("AvatarCtrl", ["$scope", "$stateParams", "Upload", "ngDialog"
($scope, $stateParams, Upload, ngDialog)->
$scope.$watch('avatar',
(avatar)->
$scope.upload($scope.avatar)
return
)
$scope.upload = (avatar)->
Upload.upload({
url: "users/avatar",
fields: { 'id': $stateParams.id }
file: avatar
})
.success(
(data, status, headers, config)->
$scope.closeThisDialog()
return
)
return
return
])
application.html.haml
!!!
%html{ "ng-app" => "inkorporated" }
%head
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%meta{ name: "viewport", content: "width=device-width, initial-scale=1" }/
%title Inkorporated
= stylesheet_link_tag 'application', media: 'all'
= javascript_include_tag 'application'
= csrf_meta_tags
%body
.container-fluid
%header{ "ng-include" => "'nav/_nav.html'" }
#page-content.container
%ui-view
From what I can see here, I think there's a very good chance that the $watch is being triggered by a model change on avatar when your dialog opens. You can pretty easily remove that watch and make that function more event driven. Looking at the ng-file-uplpad docs, it looks like there's a directive attribute to specify calling a custom function like ngf-change="myFunction()"
$scope.$watch('avatar', function(avatar) {
$scope.upload($scope.avatar);
});
For the second part of your question, I'm curious to see what code is in the SearchCtrl being called on the landing page, that POST request could easily be related to something in there
In a angularjs project, I want when user doesn't sign in, page is automatically redirect to login page. For this, I when user want see a page, if doesn't sign in before, I send 401 from rails sever by below code:
def failure
render :status => 401, :json => { :success => false, :info => "Login Credentials Failed" }
end
and I recieve this in chrome browser:
GET http://localhost:3000/api/record.json 401 (Unauthorized) angular.min.js?body=1:81
(anonymous function) angular.min.js?body=1:81
t angular.min.js?body=1:76
f angular.min.js?body=1:74
I angular.min.js?body=1:102
I angular.min.js?body=1:102
(anonymous function) angular.min.js?body=1:103
h.$eval angular.min.js?body=1:114
h.$digest angular.min.js?body=1:111
h.$apply angular.min.js?body=1:115
t angular.min.js?body=1:75
y angular.min.js?body=1:79
x.onreadystatechange
And I have below code in angularjs controller to redirect page:
'use strict';
angular.module('app',['ngRoute', 'ngResource', 'sessionService', 'recordService'])
.config(['$httpProvider', function($httpProvider){
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');
var interceptor = ['$location', '$rootScope', '$q', function($location, $rootScope, $q) {
function success(response) {
return response
};
function error(response) {
if (response.status == 401) {
$rootScope.$broadcast('event:unauthorized');
$location.path('/users/login');
return response;
};
return $q.reject(response);
};
return function(promise) {
return promise.then(success, error);
};
}];
// $httpProvider.responseInterceptors.push(interceptor);
$httpProvider.interceptors.push(interceptor);
}])
.config(['$routeProvider',function($routeProvider, $locationProvider){
$routeProvider
.when('/', {controller: 'HomeCtrl', templateUrl: '<%= asset_path('templates/index.html') %>'})
.when('/record', {controller: 'RecordCtrl', templateUrl: '<%= asset_path('templates/record/index.html') %>'})
.when('/users/login', {controller: 'UsersCtrl', templateUrl: '<%= asset_path('templates/users/login.html') %>'})
.when('/users/register', {controller: 'UsersCtrl', templateUrl: '<%= asset_path('templates/users/register.html') %>'})
.otherwise( {redirectTo: '/'});
}]);
Now when I run project and I want accept localhost:3000/#/record, I see the record page without data and page doesn't redirect to login page. How can I fix this probelm and solve it?
You can do like:
angular.module('myapp')
.factory('httpInterceptor', ['$q', '$location',function ($q, $location) {
var canceller = $q.defer();
return {
'request': function(config) {
// promise that should abort the request when resolved.
config.timeout = canceller.promise;
return config;
},
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status === 401) {
canceller.resolve('Unauthorized');
$location.url('/user/signin');
}
if (rejection.status === 403) {
canceller.resolve('Forbidden');
$location.url('/');
}
return $q.reject(rejection);
}
};
}
])
//Http Intercpetor to check auth failures for xhr requests
.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}]);
than in the route
.state('user_actions', {
abstract: true,
templateUrl: 'users/views/actions.html',
resolve: {
hasaccess: function(Sessions){
return Sessions.hasAccess('users');
}
},
controller:'UserParentActionsController'
})
.state('user_actions.create', {
url: '/user/create',
templateUrl: 'users/views/create.html',
resolve: {
groups: function(Groups){
return Groups.getList();
}
},
controller:'UserCreateController'
})
I am starting with Angularjs + rails backend and trying to fetch users data from the server - equivalent to to controller/index action in rails.
I have followed several tutorials and found this code as the most clear one....
questions
1. How to properly link angular module into views ?
2. How to fetch data using typeahead and sample data in this post.
here is plunker version of the code
Code is as follows:
views
<div ng-app='users'>
<div class='container-fluid' ng-controller="UsersIndexCtrl">
<pre>Model: {{result | json}}</pre>
<input type="text" ng-model="result" typeahead="suggestion for suggestion in users($viewValue)">
</div>
</div>
controller
<script>
// ['ui.bootstrap', 'ngResource'])
var app = angular.module('users', ['ui.bootstrap', 'ngResource']);
// factory - resources users
// equivalent to rails users/index
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
// factory - user resource
// equivalent to users show, update
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
// controller - users/ index
// equivalent to rails controller rails/index
var UsersIndexCtrl = function($scope, users) {
$scope.users = users;
};
</script>
and I am stack here, as I am getting this error:
Error: Unknown provider: usersProvider <- users
The goal of this code is to use typehead and provide data to the user.
My '/users.json' url is as follows:
[{"full_name":"Lia Cartwright","id":1,"image_url":"no-icon.jpg"},{"full_name":"Hilton Turner","id":2,"image_url":"no-icon.jpg"},{"full_name":"Aubrey Barrows","id":3,"image_url":"no-icon.jpg"},{"full_name":"Donnie Kris","id":4,"image_url":"no-icon.jpg"},{"full_name":"Eryn Rath","id":5,"image_url":"no-icon.jpg"},{"full_name":"Caden Fay","id":6,"image_url":"no-icon.jpg"},{"full_name":"Arlie Tromp","id":7,"image_url":"no-icon.jpg"},{"full_name":"Rico Klein","id":8,"image_url":"no-icon.jpg"},{"full_name":"Gudrun Dare","id":9,"image_url":"no-icon.jpg"},{"full_name":"Nathan Langworth","id":10,"image_url":"no-icon.jpg"},{"full_name":"Deanna Stroman","id":11,"image_url":"no-icon.jpg"},{"full_name":"Shania Stroman","id":12,"image_url":"no-icon.jpg"},{"full_name":"Lupe Harvey","id":13,"image_url":"no-icon.jpg"},{"full_name":"Constance Armstrong","id":14,"image_url":"no-icon.jpg"},{"full_name":"Reagan Tremblay","id":15,"image_url":"no-icon.jpg"},{"full_name":"Murray Sipes","id":16,"image_url":"no-icon.jpg"},{"full_name":"Dandre Klocko","id":17,"image_url":"no-icon.jpg"},{"full_name":"Haylee Monahan","id":18,"image_url":"no-icon.jpg"},{"full_name":"Florence Harber","id":19,"image_url":"no-icon.jpg"},{"full_name":"Norberto Hoppe","id":20,"image_url":"no-icon.jpg"}]
You must inject Users not users, it's case sensitive.
Side notes:
No need to create two models, replace:
app.factory('Users', function($resource) {
return $resource('/users.json', {}, {
index: { method: 'GET', isArray: true}
});
});
app.factory('User', function($resource) {
return $resource('/users/:user_id.json', {}, {
show: { method: 'GET' },
update: { method: 'PUT' }
});
});
with:
app.factory('User', function($resource) {
return $resource("users/:id", { id: '#id' }, {
index: { method: 'GET', isArray: true, responseType: 'json' },
show: { method: 'GET', responseType: 'json' },
update: { method: 'PUT', responseType: 'json' }
});
})
Other thing, in your controller, do:
var UsersIndexCtrl = function($scope, User) {
$scope.users = User.index();
};
Last thing, consider using: Angular Rails resource