├── .bowerrc ├── .editorconfig ├── .ember-cli ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Brocfile.js ├── README.md ├── app ├── adapters │ └── application.js ├── app.js ├── components │ ├── .gitkeep │ ├── microposts-index.js │ └── users-list.js ├── controllers │ ├── .gitkeep │ ├── index.js │ ├── login.js │ ├── micropost │ │ └── index.js │ ├── microposts │ │ └── index.js │ ├── user │ │ ├── edit.js │ │ ├── followers.js │ │ ├── following.js │ │ └── index.js │ └── users │ │ ├── index.js │ │ └── new.js ├── helpers │ ├── .gitkeep │ └── time-ago.js ├── index.html ├── initializers │ └── custom-session.js ├── models │ ├── .gitkeep │ ├── micropost.js │ └── user.js ├── router.js ├── routes │ ├── .gitkeep │ ├── application.js │ ├── index.js │ ├── login.js │ ├── user.js │ ├── user │ │ ├── edit.js │ │ ├── followers.js │ │ ├── following.js │ │ └── index.js │ └── users │ │ ├── index.js │ │ └── new.js ├── styles │ └── app.scss ├── templates │ ├── about.hbs │ ├── application.hbs │ ├── components │ │ ├── .gitkeep │ │ ├── microposts-index.hbs │ │ ├── page-numbers.hbs │ │ ├── user-profile.hbs │ │ └── users-list.hbs │ ├── contact.hbs │ ├── help.hbs │ ├── index.hbs │ ├── login.hbs │ ├── microposts │ │ ├── feed.hbs │ │ └── index.hbs │ ├── user │ │ ├── edit.hbs │ │ ├── followers.hbs │ │ ├── following.hbs │ │ └── index.hbs │ └── users │ │ ├── index.hbs │ │ └── new.hbs └── views │ └── .gitkeep ├── bower.json ├── config └── environment.js ├── package.json ├── public ├── .gitkeep ├── crossdomain.xml └── robots.txt ├── testem.json ├── tests ├── .jshintrc ├── helpers │ ├── resolver.js │ └── start-app.js ├── index.html ├── test-helper.js └── unit │ ├── .gitkeep │ ├── adapters │ └── application-test.js │ ├── components │ └── microposts-index-test.js │ ├── helpers │ └── time-ago-test.js │ └── initializers │ └── custom-session-test.js └── vendor └── .gitkeep /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.js] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.hbs] 21 | indent_style = space 22 | indent_size = 2 23 | 24 | [*.css] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | [*.html] 29 | indent_style = space 30 | indent_size = 2 31 | 32 | [*.md] 33 | trim_trailing_whitespace = false 34 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log 17 | testem.log 18 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "-Promise" 6 | ], 7 | "browser": true, 8 | "boss": true, 9 | "curly": true, 10 | "debug": false, 11 | "devel": true, 12 | "eqeqeq": true, 13 | "evil": true, 14 | "forin": false, 15 | "immed": false, 16 | "laxbreak": false, 17 | "newcap": true, 18 | "noarg": true, 19 | "noempty": false, 20 | "nonew": false, 21 | "nomen": false, 22 | "onevar": false, 23 | "plusplus": false, 24 | "regexp": false, 25 | "undef": true, 26 | "sub": true, 27 | "strict": false, 28 | "white": false, 29 | "eqnull": true, 30 | "esnext": true, 31 | "unused": true 32 | } 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | 4 | sudo: false 5 | 6 | cache: 7 | directories: 8 | - node_modules 9 | 10 | before_install: 11 | - "npm config set spin false" 12 | - "npm install -g npm@^2" 13 | 14 | install: 15 | - npm install -g bower 16 | - npm install 17 | - bower install 18 | 19 | script: 20 | - npm test 21 | -------------------------------------------------------------------------------- /Brocfile.js: -------------------------------------------------------------------------------- 1 | /* global require, module */ 2 | 3 | var EmberApp = require('ember-cli/lib/broccoli/ember-app'); 4 | 5 | var app = new EmberApp(); 6 | 7 | // Use `app.import` to add additional libraries to the generated 8 | // output files. 9 | // 10 | // If you need to use different assets in different 11 | // environments, specify an object as the first parameter. That 12 | // object's keys should be the environment name and the values 13 | // should be the asset to use in that environment. 14 | // 15 | // If the library that you are including contains AMD or ES6 16 | // modules that you would like to import into your application 17 | // please specify an object with the list of modules as keys 18 | // along with the exports of each module as its value. 19 | 20 | 21 | app.import('bower_components/jquery/dist/jquery.min.js'); 22 | app.import('bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js'); 23 | 24 | module.exports = app.toTree(); 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rails-tutorial-ember 2 | **This repo is deprecated and not actively maintained. 3 | A new [Rails tutorial](https://github.com/vasilakisfil/rails5_api_tutorial) has been released based on Rails 5. The equivelant EmberJS app can be found [here](https://github.com/vasilakisfil/ember_on_rails5).** 4 | 5 | Michael Hart's Rails tutorial.. on Ember! Check the [rails backend API](https://github.com/vasilakisfil/rails_tutorial_api). 6 | Deployed [here](https://ember-on-rails-tutorial.herokuapp.com) 7 | 8 | ## Prerequisites 9 | 10 | You will need the following things properly installed on your computer. 11 | 12 | * [Git](http://git-scm.com/) 13 | * [Node.js](http://nodejs.org/) (with NPM) and [Bower](http://bower.io/) 14 | 15 | ## Installation 16 | 17 | * `git clone ` this repository 18 | * change into the new directory 19 | * `npm install` 20 | * `bower install` 21 | 22 | ## Running / Development 23 | 24 | * `ember server` 25 | * Visit your app at [http://localhost:4200](http://localhost:4200). 26 | 27 | ### Code Generators 28 | 29 | Make use of the many generators for code, try `ember help generate` for more details 30 | 31 | ### Running Tests 32 | 33 | * `ember test` 34 | * `ember test --server` 35 | 36 | ### Building 37 | 38 | * `ember build` (development) 39 | * `ember build --environment production` (production) 40 | 41 | ### Deploying 42 | 43 | Specify what it takes to deploy your app. 44 | 45 | ## Further Reading / Useful Links 46 | 47 | * [ember.js](http://emberjs.com/) 48 | * [ember-cli](http://www.ember-cli.com/) 49 | * Development Browser Extensions 50 | * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) 51 | * [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/) 52 | 53 | -------------------------------------------------------------------------------- /app/adapters/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import DS from 'ember-data'; 3 | import ENV from 'rails-tutorial-ember/config/environment'; 4 | 5 | export default DS.ActiveModelAdapter.extend({ 6 | namespace: 'api/v1', 7 | host: ENV.APP.SERVER_URL, 8 | 9 | pathForType: function(type) { 10 | var decamelized = Ember.String.decamelize(type); 11 | if (this.plurals()[decamelized]) { 12 | return this.plurals()[decamelized]; 13 | } else { 14 | return Ember.String.pluralize(decamelized); 15 | } 16 | }, 17 | 18 | plurals: function() { 19 | return {'feed': 'feed'}; 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from 'ember/resolver'; 3 | import loadInitializers from 'ember/load-initializers'; 4 | import config from './config/environment'; 5 | 6 | Ember.MODEL_FACTORY_INJECTIONS = true; 7 | 8 | var App = Ember.Application.extend({ 9 | modulePrefix: config.modulePrefix, 10 | podModulePrefix: config.podModulePrefix, 11 | Resolver: Resolver, 12 | LOG_TRANSITIONS: true, 13 | ready: function() { 14 | this.devTools.globalize(); 15 | } 16 | }); 17 | 18 | loadInitializers(App, config.modulePrefix); 19 | 20 | export default App; 21 | -------------------------------------------------------------------------------- /app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/components/.gitkeep -------------------------------------------------------------------------------- /app/components/microposts-index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Component.extend({ 4 | }); 5 | -------------------------------------------------------------------------------- /app/components/users-list.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Component.extend({ 4 | showTopPageNumbers: true, 5 | showBottomPageNumbers: true 6 | }); 7 | -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/controllers/.gitkeep -------------------------------------------------------------------------------- /app/controllers/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ObjectController.extend({ 4 | needs: ['microposts/index'], 5 | 6 | actions: { 7 | createMicropost: function() { 8 | var _this = this; 9 | this.get('micropost').save().then(function(micropost) { 10 | _this.get('controllers.microposts/index.model.content').unshiftObject(micropost); 11 | _this.set('micropost', _this.store.createRecord('micropost', {user: micropost.get('user')})); 12 | }); 13 | } 14 | } 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /app/controllers/login.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin'; 3 | 4 | export default Ember.Controller.extend(LoginControllerMixin, { 5 | authenticator: 'simple-auth-authenticator:devise', 6 | }); 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/controllers/micropost/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ObjectController.extend({ 4 | needs: ['microposts/index'], 5 | 6 | isAuthor: function() { 7 | if (this.get('session.id').toString() === this.get('model.user.id').toString()) { 8 | return true; 9 | } else { return false; } 10 | }.property(), 11 | 12 | actions: { 13 | deleteMicropost: function() { 14 | this.get('controllers.microposts/index.model.content').shiftObject(this.get('model')); 15 | this.get('model').destroyRecord(); 16 | } 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /app/controllers/microposts/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ArrayController.extend({ 4 | itemController: 'micropost/index', 5 | // setup our query params 6 | queryParams: ["page", "perPage"], 7 | 8 | // binding the property on the paged array 9 | // to the query params on the controller 10 | pageBinding: "content.page", 11 | perPageBinding: "content.perPage", 12 | totalPagesBinding: "content.totalPages", 13 | 14 | // set default values, can cause problems if left out 15 | // if value matches default, it won't display in the URL 16 | page: 1, 17 | 18 | totalMicroposts: function() { 19 | return this.get('store').metadataFor('micropost').total_count; 20 | }.property('model') 21 | }); 22 | -------------------------------------------------------------------------------- /app/controllers/user/edit.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ObjectController.extend({ 4 | actions: { 5 | updateUser: function() { 6 | this.get('model').save().then(function() { 7 | this.notify.success('Profile updated'); 8 | 9 | //some custom logic cause response doesn't return any password/passwordConfirmation 10 | //and ember merges these data with the response 11 | this.set('model.password', null); 12 | this.set('model.passwordConfirmation', null); 13 | }.bind(this), function() {}); 14 | } 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /app/controllers/user/followers.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ArrayController.extend({ 4 | 5 | }); 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/controllers/user/following.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ArrayController.extend({ 4 | 5 | }); 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/controllers/user/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ObjectController.extend({ 4 | isCurrentUser: function() { 5 | if (this.get('session.currentUser.id') === this.get('model.id')) { return true; } 6 | }.property('model.id'), 7 | 8 | isFollower: function() { 9 | if (this.get('session.currentUser.followings').findBy('id', this.get('model.id'))) { 10 | this.set('isFollower', true); 11 | } else { 12 | this.set('isFollower', false); 13 | } 14 | }.property(), 15 | 16 | isFollowerObserver: function() { 17 | if (this.get('session.currentUser.followings').findBy('id', this.get('model.id'))) { 18 | this.set('isFollower', true); 19 | } else { 20 | this.set('isFollower', false); 21 | } 22 | }.observes('session.currentUser.followers'), 23 | 24 | 25 | actions: { 26 | followUser: function() { 27 | var _this = this; 28 | 29 | this._adapter().ajax(this._followingUrl(), 'POST').then(function() { 30 | _this.set('isFollower', true); 31 | _this.get('model.followers').pushObject(_this.get('session.currentUser')); 32 | }); 33 | 34 | }, 35 | 36 | unfollowUser: function() { 37 | var _this = this; 38 | 39 | this._adapter().ajax(this._followingUrl(), 'DELETE').then(function() { 40 | _this.set('isFollower', false); 41 | _this.get('model.followers').removeObject(_this.get('session.currentUser')); 42 | }); 43 | } 44 | }, 45 | 46 | _followingUrl: function() { 47 | var followingUrl = '/links/following/' + this.get('model.id'); 48 | return this._adapter().buildURL('user', this.get('session.id')) + followingUrl; 49 | }, 50 | 51 | _adapter: function() { 52 | return this.get('store').adapterFor('application'); 53 | } 54 | }); 55 | 56 | -------------------------------------------------------------------------------- /app/controllers/users/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ArrayController.extend({ 4 | // setup our query params 5 | queryParams: ["page", "perPage"], 6 | 7 | // binding the property on the paged array 8 | // to the query params on the controller 9 | pageBinding: "content.page", 10 | perPageBinding: "content.perPage", 11 | totalPagesBinding: "content.totalPages", 12 | 13 | // set default values, can cause problems if left out 14 | // if value matches default, it won't display in the URL 15 | page: 1, 16 | 17 | actions: { 18 | deleteUser: function(user) { 19 | if (confirm("You sure?") === true) { 20 | user.destroyRecord(); 21 | } 22 | } 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /app/controllers/users/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.ObjectController.extend({ 4 | actions: { 5 | createUser: function() { 6 | this.get('model').save().then(function() { 7 | this.notify.success('Your account has been created. Please sign in.', { 8 | closeAfter: 5000 9 | }); 10 | this.transitionToRoute('index'); 11 | }.bind(this), function() {}); 12 | } 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/helpers/.gitkeep -------------------------------------------------------------------------------- /app/helpers/time-ago.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | function timeAgo(timeObject) { 4 | var seconds = Math.floor((new Date() - timeObject) / 1000); 5 | var interval = Math.floor(seconds / 31536000); 6 | 7 | 8 | if (interval > 1) { 9 | return interval + " years ago"; 10 | } 11 | interval = Math.floor(seconds / 2592000); 12 | if (interval > 1) { 13 | return interval + " months ago"; 14 | } 15 | interval = Math.floor(seconds / 86400); 16 | if (interval > 1) { 17 | return interval + " days ago"; 18 | } 19 | interval = Math.floor(seconds / 3600); 20 | if (interval > 1) { 21 | return interval + " hours ago"; 22 | } 23 | interval = Math.floor(seconds / 60); 24 | if (interval > 1) { 25 | return interval + " minutes ago"; 26 | } 27 | return Math.floor(seconds) + " seconds ago"; 28 | } 29 | 30 | export default Ember.Handlebars.makeBoundHelper(timeAgo); 31 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RailsTutorialEmber 7 | 8 | 9 | 10 | {{content-for 'head'}} 11 | 12 | 13 | 14 | 15 | {{content-for 'head-footer'}} 16 | 17 | 18 | {{content-for 'body'}} 19 | 20 | 21 | 22 | 23 | {{content-for 'body-footer'}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/initializers/custom-session.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Session from 'simple-auth/session'; 3 | 4 | export function initialize(container) { 5 | Session.reopen({ 6 | setCurrentUser: function() { 7 | var id = this.get('id'); 8 | var _this = this; 9 | 10 | if (!Ember.isEmpty(id)) { 11 | return container.lookup('store:main').find('user', id) 12 | .then(function(user) { 13 | _this.set('currentUser', user); 14 | }); 15 | } 16 | }.observes('id') 17 | }); 18 | } 19 | 20 | export default { 21 | name: 'custom-session', 22 | before: 'simple-auth', 23 | initialize: initialize 24 | }; 25 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/micropost.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | content: DS.attr('string'), 5 | picture: DS.attr('string'), //we might change that to pictureUrl 6 | 7 | createdAt: DS.attr('date'), 8 | updatedAt: DS.attr('date'), 9 | 10 | user: DS.belongsTo('user', {async: true}), 11 | 12 | pictureUrl: function() { 13 | return 'http://localhost:3000/' + this.get('picture'); 14 | }.property('picture') 15 | }); 16 | -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | activated: DS.attr('boolean'), 5 | activatedAt: DS.attr('date'), 6 | admin: DS.attr('boolean'), 7 | email: DS.attr('string'), 8 | name: DS.attr('string'), 9 | 10 | password: DS.attr('string'), 11 | passwordConfirmation: DS.attr('string'), 12 | 13 | created_at: DS.attr('date'), 14 | updated_at: DS.attr('date'), 15 | 16 | 17 | microposts: DS.hasMany('micropost', {async: true}), 18 | followings: DS.hasMany('user', {inverse: 'followers', async: true}), 19 | followers: DS.hasMany('user', {inverse: 'followings', async: true}) 20 | }); 21 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from './config/environment'; 3 | 4 | var Router = Ember.Router.extend({ 5 | location: config.locationType 6 | }); 7 | 8 | Router.map(function() { 9 | this.route('help'); 10 | this.route('about'); 11 | this.route('contact'); 12 | this.route('login'); 13 | this.route('logout'); 14 | this.route('users.new', {path: '/signup'}); 15 | this.resource('users', function() { 16 | this.resource('user', { path: ':user_id'}, function() { 17 | this.route('edit'); 18 | this.route('followers'); 19 | this.route('following'); 20 | }); 21 | }); 22 | }); 23 | 24 | export default Router; 25 | -------------------------------------------------------------------------------- /app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/routes/.gitkeep -------------------------------------------------------------------------------- /app/routes/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin'; 3 | 4 | export default Ember.Route.extend(ApplicationRouteMixin, { 5 | beforeModel: function(transition) { 6 | if(transition.targetName === 'login' && this.get('session.isAuthenticated')) { 7 | this.transitionTo('index'); 8 | } else { 9 | // Bubble the `willTransition` action so that 10 | // parent routes can decide whether or not to abort. 11 | return true; 12 | } 13 | }, 14 | 15 | actions: { 16 | error: function (errorObject) { 17 | if (errorObject) { 18 | if (errorObject.status === 401) { 19 | return this.transitionTo('login'); 20 | } 21 | } 22 | else { return true; } 23 | } 24 | } 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /app/routes/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | 4 | export default Ember.Route.extend(RouteMixin, { 5 | model: function() { 6 | return {}; 7 | }, 8 | 9 | setupController: function(controller, model) { 10 | var _this = this; 11 | controller.set('model', model); 12 | if (this.get('session.isAuthenticated')) { 13 | //this part will be replaced with the user saved in the session 14 | this.store.find('user', this.get('session.id')).then(function(user) { 15 | controller.set('user', user); 16 | controller.set( 17 | 'micropost', 18 | _this.store.createRecord('micropost', {user: user})); 19 | }); 20 | } 21 | }, 22 | 23 | perPage: 30, 24 | 25 | afterModel: function() { 26 | var _this = this; 27 | if (this.get('session.isAuthenticated')) { 28 | this.findPaged('micropost', {feed_user_id: this.get('session.id'), feed: true}).then(function(microposts) { 29 | _this.controllerFor('microposts/index').setProperties({ 30 | model: microposts, 31 | content: microposts 32 | }); 33 | }); 34 | } 35 | }, 36 | 37 | renderTemplate: function() { 38 | this.render('index', {}); 39 | 40 | if (this.get('session.isAuthenticated')) { 41 | this.render('microposts/feed', { 42 | into: 'index', 43 | outlet: 'side-list', 44 | controller: 'microposts/index' 45 | }); 46 | } 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /app/routes/login.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin'; 3 | 4 | export default Ember.Route.extend(ApplicationRouteMixin, { 5 | deactivate: function() { 6 | this.controllerFor('login').set('loginError', false); 7 | }, 8 | actions: { 9 | sessionAuthenticationSucceeded: function() { 10 | this.transitionTo('index'); 11 | }, 12 | sessionAuthenticationFailed: function() { 13 | this.controllerFor('login').set('loginError', true); 14 | } 15 | } 16 | }); 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/routes/user.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | model: function(params) { 5 | return this.store.find('user', params.user_id); 6 | } 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /app/routes/user/edit.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin'; 4 | 5 | export default Ember.Route.extend(RouteMixin, AuthenticatedRouteMixin, { 6 | model: function() { 7 | return this.modelFor('user'); 8 | } 9 | }); 10 | 11 | -------------------------------------------------------------------------------- /app/routes/user/followers.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | 4 | export default Ember.Route.extend(RouteMixin, { 5 | model: function() { 6 | this.controllerFor('user/index').setProperties({ 7 | model: this.modelFor('user'), 8 | gravatarUsers: this.modelFor('user').get('followers') 9 | }); 10 | }, 11 | 12 | perPage: 30, 13 | 14 | afterModel: function() { 15 | var _this = this; 16 | this.findPaged('user', { 17 | follower_id: this.modelFor('user').id 18 | }).then(function(followers) { 19 | Ember.Logger.debug(followers); 20 | _this.controllerFor('user/followers').setProperties({ 21 | model: followers, 22 | content: followers 23 | }); 24 | }); 25 | }, 26 | 27 | 28 | renderTemplate: function() { 29 | this.render('user/index', {}); 30 | 31 | this.render('user/followers', { 32 | into: 'user/index', 33 | outlet: 'side-list', 34 | controller: 'user/followers' 35 | }); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /app/routes/user/following.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | 4 | export default Ember.Route.extend(RouteMixin, { 5 | model: function() { 6 | this.controllerFor('user/index').setProperties({ 7 | model: this.modelFor('user'), 8 | gravatarUsers: this.modelFor('user').get('followings') 9 | }); 10 | }, 11 | 12 | perPage: 30, 13 | 14 | afterModel: function() { 15 | var _this = this; 16 | this.findPaged('user', { 17 | following_id: this.modelFor('user').id 18 | }).then(function(followers) { 19 | Ember.Logger.debug(followers); 20 | _this.controllerFor('user/following').setProperties({ 21 | model: followers, 22 | content: followers 23 | }); 24 | }); 25 | }, 26 | 27 | 28 | renderTemplate: function() { 29 | this.render('user/index', {}); 30 | 31 | this.render('user/following', { 32 | into: 'user/index', 33 | outlet: 'side-list', 34 | controller: 'user/following' 35 | }); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /app/routes/user/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | 4 | export default Ember.Route.extend(RouteMixin, { 5 | model: function() { 6 | return this.modelFor('user'); 7 | }, 8 | 9 | perPage: 30, 10 | 11 | afterModel: function(user) { 12 | var _this = this; 13 | this.findPaged('micropost', {user_id: user.id}).then(function(microposts) { 14 | _this.controllerFor('microposts/index').setProperties({ 15 | model: microposts, 16 | content: microposts 17 | }); 18 | }); 19 | }, 20 | 21 | setupController: function(controller, model) { 22 | controller.set('model', model); 23 | }, 24 | 25 | renderTemplate: function() { 26 | this.render('user/index', {}); 27 | 28 | this.render('microposts/index', { 29 | into: 'user/index', 30 | outlet: 'side-list', 31 | controller: 'microposts/index' 32 | }); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /app/routes/users/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import RouteMixin from 'ember-cli-pagination/remote/route-mixin'; 3 | 4 | export default Ember.Route.extend(RouteMixin, { 5 | // optional. default is 10 6 | perPage: 30, 7 | 8 | model: function(params) { 9 | // todo is your model name 10 | // returns a PagedRemoteArray 11 | return this.findPaged('user', params); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /app/routes/users/new.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | model: function() { 5 | return this.store.createRecord('user', {}); 6 | } 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import 'bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap'; 2 | 3 | /* mixins, variables, etc. */ 4 | 5 | $gray-medium-light: #eaeaea; 6 | 7 | @mixin box_sizing { 8 | -moz-box-sizing: border-box; 9 | -webkit-box-sizing: border-box; 10 | box-sizing: border-box; 11 | } 12 | 13 | /* universal */ 14 | 15 | html { 16 | overflow-y: scroll; 17 | } 18 | 19 | body { 20 | padding-top: 60px; 21 | } 22 | 23 | section { 24 | overflow: auto; 25 | } 26 | 27 | textarea { 28 | resize: vertical; 29 | } 30 | 31 | .center { 32 | text-align: center; 33 | h1 { 34 | margin-bottom: 60px; 35 | } 36 | } 37 | 38 | 39 | /* typography */ 40 | 41 | h1, h2, h3, h4, h5, h6 { 42 | line-height: 1; 43 | } 44 | 45 | h1 { 46 | font-size: 3em; 47 | letter-spacing: -2px; 48 | margin-bottom: 30px; 49 | text-align: center; 50 | } 51 | 52 | h2 { 53 | font-size: 1.2em; 54 | letter-spacing: -1px; 55 | margin-bottom: 30px; 56 | text-align: center; 57 | font-weight: normal; 58 | color: $gray-light; 59 | } 60 | 61 | p { 62 | font-size: 1.1em; 63 | line-height: 1.7em; 64 | } 65 | 66 | /* header */ 67 | 68 | #logo { 69 | float: left; 70 | margin-right: 10px; 71 | font-size: 1.7em; 72 | color: white; 73 | text-transform: uppercase; 74 | letter-spacing: -1px; 75 | padding-top: 9px; 76 | font-weight: bold; 77 | &:hover { 78 | color: white; 79 | text-decoration: none; 80 | } 81 | } 82 | 83 | /* footer */ 84 | 85 | footer { 86 | margin-top: 45px; 87 | padding-top: 5px; 88 | border-top: 1px solid $gray-medium-light; 89 | color: $gray-light; 90 | a { 91 | color: $gray; 92 | &:hover { 93 | color: $gray-darker; 94 | } 95 | } 96 | small { 97 | float: left; 98 | } 99 | ul { 100 | float: right; 101 | list-style: none; 102 | li { 103 | float: left; 104 | margin-left: 15px; 105 | } 106 | } 107 | } 108 | 109 | /* miscellaneous */ 110 | 111 | .debug_dump { 112 | clear: both; 113 | float: left; 114 | width: 100%; 115 | margin-top: 45px; 116 | @include box_sizing; 117 | } 118 | 119 | /* sidebar */ 120 | 121 | aside { 122 | section.user_info { 123 | margin-top: 20px; 124 | } 125 | section { 126 | padding: 10px 0; 127 | margin-top: 20px; 128 | &:first-child { 129 | border: 0; 130 | padding-top: 0; 131 | } 132 | span { 133 | display: block; 134 | margin-bottom: 3px; 135 | line-height: 1; 136 | } 137 | h1 { 138 | font-size: 1.4em; 139 | text-align: left; 140 | letter-spacing: -1px; 141 | margin-bottom: 3px; 142 | margin-top: 0px; 143 | } 144 | } 145 | } 146 | 147 | .gravatar { 148 | float: left; 149 | margin-right: 10px; 150 | } 151 | 152 | .gravatar_edit { 153 | margin-top: 15px; 154 | } 155 | 156 | .stats { 157 | overflow: auto; 158 | margin-top: 0; 159 | padding: 0; 160 | a { 161 | float: left; 162 | padding: 0 10px; 163 | border-left: 1px solid $gray-lighter; 164 | color: gray; 165 | &:first-child { 166 | padding-left: 0; 167 | border: 0; 168 | } 169 | &:hover { 170 | text-decoration: none; 171 | color: blue; 172 | } 173 | } 174 | strong { 175 | display: block; 176 | } 177 | } 178 | 179 | .user_avatars { 180 | overflow: auto; 181 | margin-top: 10px; 182 | .gravatar { 183 | margin: 1px 1px; 184 | } 185 | a { 186 | padding: 0; 187 | } 188 | } 189 | 190 | .users.follow { 191 | padding: 0; 192 | } 193 | 194 | /* forms */ 195 | 196 | input, textarea, select, .uneditable-input { 197 | border: 1px solid #bbb; 198 | width: 100%; 199 | margin-bottom: 15px; 200 | @include box_sizing; 201 | } 202 | 203 | input { 204 | height: auto !important; 205 | } 206 | 207 | #error_explanation { 208 | color: red; 209 | ul { 210 | color: red; 211 | margin: 0 0 30px 0; 212 | } 213 | } 214 | 215 | .field_with_errors { 216 | @extend .has-error; 217 | .form-control { 218 | color: $state-danger-text; 219 | } 220 | } 221 | 222 | .checkbox { 223 | margin-top: -10px; 224 | margin-bottom: 10px; 225 | span { 226 | margin-left: 20px; 227 | font-weight: normal; 228 | } 229 | } 230 | 231 | #session_remember_me { 232 | width: auto; 233 | margin-left: 0; 234 | } 235 | 236 | /* Users index */ 237 | .users { 238 | list-style: none; 239 | margin: 0; 240 | li { 241 | overflow: auto; 242 | padding: 10px 0; 243 | border-bottom: 1px solid $gray-lighter; 244 | } 245 | } 246 | 247 | /* microposts */ 248 | 249 | .microposts { 250 | list-style: none; 251 | padding: 0; 252 | li { 253 | padding: 10px 0; 254 | border-top: 1px solid #e8e8e8; 255 | } 256 | .user { 257 | margin-top: 5em; 258 | padding-top: 0; 259 | } 260 | .content { 261 | display: block; 262 | margin-left: 60px; 263 | img { 264 | display: block; 265 | padding: 5px 0; 266 | } 267 | } 268 | .timestamp { 269 | color: $gray-light; 270 | display: block; 271 | margin-left: 60px; 272 | } 273 | .gravatar { 274 | float: left; 275 | margin-right: 10px; 276 | margin-top: 5px; 277 | } 278 | } 279 | 280 | aside { 281 | textarea { 282 | height: 100px; 283 | margin-bottom: 5px; 284 | } 285 | } 286 | 287 | span.picture { 288 | margin-top: 10px; 289 | input { 290 | border: 0; 291 | } 292 | } 293 | 294 | .ember-logo { 295 | width: 111px; 296 | height: auto; 297 | } 298 | -------------------------------------------------------------------------------- /app/templates/about.hbs: -------------------------------------------------------------------------------- 1 |

About

2 |

3 | This app is a fork of Ruby on Rails 4 | Tutorial built on Ember. The backend is still built on Rails by extending the Rails tutorial app. 5 |

6 | 7 | 8 |

9 | You can find more info in the github repositories: 10 | rails_tutorial_ember and rails_tutorial_api. 11 |

12 | -------------------------------------------------------------------------------- /app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | 30 | {{ember-notify messageStyle='bootstrap'}} 31 |
32 | {{outlet}} 33 | 34 | 48 |
49 | -------------------------------------------------------------------------------- /app/templates/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/templates/components/.gitkeep -------------------------------------------------------------------------------- /app/templates/components/microposts-index.hbs: -------------------------------------------------------------------------------- 1 | {{#if model.length}} 2 | {{#if title}} 3 |

{{title}}

4 | {{else}} 5 |

Microposts ({{totalMicroposts}})

6 | {{/if}} 7 |
    8 | {{#each micropost in model itemController='micropost/index'}} 9 |
  1. 10 | {{gravatar-image email=micropost.user.email alt=micropost.user.name size=50 class='gravatar'}} 11 | 12 | {{link-to micropost.user.name 'user.index' micropost.user.id}} 13 | 14 | {{! here .content delegates to the proxy object content/model}} 15 | {{micropost.content.content}} 16 | {{#if micropost.picture}} 17 | 18 | {{/if}} 19 | 20 | 21 | Posted about {{time-ago micropost.createdAt}}. 22 | {{#if micropost.isAuthor}} 23 | delete 24 | {{/if}} 25 | 26 |
  2. 27 | 28 | {{/each}} 29 |
30 | 31 | {{page-numbers content=model numPagesToShow=4}} 32 | {{/if}} 33 | 34 | -------------------------------------------------------------------------------- /app/templates/components/page-numbers.hbs: -------------------------------------------------------------------------------- 1 |
2 | 35 |
36 | -------------------------------------------------------------------------------- /app/templates/components/user-profile.hbs: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{gravatar-image email=model.email alt=model.name size=80 class='gravatar'}} 4 | {{model.name}} 5 |

6 |
7 | 8 |
9 |
10 | {{#link-to 'user.following' model}} 11 | 12 | {{model.followings.length}} 13 | 14 | following 15 | {{/link-to}} 16 | 17 | {{#link-to 'user.followers' model}} 18 | 19 | {{model.followers.length}} 20 | 21 | followers 22 | {{/link-to}} 23 |
24 |
25 | {{#each follower in gravatarUsers}} 26 | {{#link-to 'user.index' follower.id}} 27 | {{gravatar-image email=follower.email alt=follower.name size=30 class='gravatar'}} 28 | {{/link-to}} 29 | {{/each}} 30 |
31 |
32 | -------------------------------------------------------------------------------- /app/templates/components/users-list.hbs: -------------------------------------------------------------------------------- 1 | {{#if showTopPageNumbers}} 2 | {{page-numbers content=model numPagesToShow=4}} 3 | {{/if}} 4 |
5 | 13 |
14 | {{#if showBottomPageNumbers}} 15 | {{page-numbers content=model numPagesToShow=4}} 16 | {{/if}} 17 | 18 | -------------------------------------------------------------------------------- /app/templates/contact.hbs: -------------------------------------------------------------------------------- 1 |

Contact

2 |

3 | Open a gihub issue in the repositories 4 | rails_tutorial_ember and rails_tutorial_api. 5 |

6 | -------------------------------------------------------------------------------- /app/templates/help.hbs: -------------------------------------------------------------------------------- 1 |

Help

2 |

3 | Open a gihub issue in the repositories 4 | rails_tutorial_ember and rails_tutorial_api. 5 |

6 | 7 | -------------------------------------------------------------------------------- /app/templates/index.hbs: -------------------------------------------------------------------------------- 1 | {{#if session.isAuthenticated}} 2 |
3 | 15 |
16 | {{! <%= render 'follow_form' if logged_in? %> }} 17 | {{outlet 'side-list'}} 18 |
19 |
20 | {{else}} 21 |
22 |

Welcome to the Sample App

23 | 24 |

25 | This is the home page for the 26 | Ember on Rails Tutorial 27 | sample application. 28 |

29 | 30 | {{link-to "Sign up now!" 'users.new' class="btn btn-lg btn-primary"}} 31 |
32 | 33 | 34 | 35 | 36 | 37 | {{/if}} 38 | 39 | -------------------------------------------------------------------------------- /app/templates/login.hbs: -------------------------------------------------------------------------------- 1 |

Log in

2 | 3 |
4 |
5 | 6 | {{#if loginError}} 7 |
8 |
9 | Invalid email/password combination 10 |
11 |
12 | {{/if}} 13 | 14 |
15 | 16 | {{input class="form-control" type="email" id="user_email" value=identification size="50"}} 17 | 18 | {{link-to '(forgot password)' 'users.new'}} 19 | {{input class="form-control" type="password" id="user_password" value=password size="50"}} 20 | 24 | 25 |
26 |

New user? {{link-to 'Sign up now!' 'users.new'}}

27 |
28 |
29 | -------------------------------------------------------------------------------- /app/templates/microposts/feed.hbs: -------------------------------------------------------------------------------- 1 | {{microposts-index 2 | title="Micropost Feed" 3 | model=model 4 | }} 5 | -------------------------------------------------------------------------------- /app/templates/microposts/index.hbs: -------------------------------------------------------------------------------- 1 | {{microposts-index 2 | model=model 3 | totalMicroposts=totalMicroposts 4 | }} 5 | -------------------------------------------------------------------------------- /app/templates/user/edit.hbs: -------------------------------------------------------------------------------- 1 |

Update your profile

2 | 3 |
4 |
5 | 6 | {{#if errors.messages}} 7 |
8 |
9 | The form contains {{errors.messages.length}} errors. 10 |
11 | {{#each error in errors.messages}} 12 |
    13 |
  • {{error.attribute}} {{error.message}}
  • 14 |
15 | {{/each}} 16 |
17 | {{/if}} 18 | 19 |
20 | 21 | {{input class="form-control" type="text" id="user_name" value=name size="50"}} 22 | 23 | 24 | {{input class="form-control" type="text" id="user_email" value=email size="50"}} 25 | 26 | 27 | {{input class="form-control" type="password" id="user_password" value=password size="50"}} 28 | 29 | 30 | {{input class="form-control" type="password" id="user_password_confirmation" value=passwordConfirmation size="50"}} 31 | 32 | 33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /app/templates/user/followers.hbs: -------------------------------------------------------------------------------- 1 | {{users-list 2 | model=model 3 | showTopPageNumbers=false 4 | }} 5 | -------------------------------------------------------------------------------- /app/templates/user/following.hbs: -------------------------------------------------------------------------------- 1 | {{users-list 2 | model=model 3 | showTopPageNumbers=false 4 | }} 5 | -------------------------------------------------------------------------------- /app/templates/user/index.hbs: -------------------------------------------------------------------------------- 1 |
2 | 5 |
6 | {{#unless isCurrentUser}} 7 |
8 |
9 | {{#if isFollower}} 10 | 11 | {{else}} 12 | 13 | {{/if}} 14 |
15 |
16 | {{/unless}} 17 | {{outlet 'side-list'}} 18 |
19 |
20 | -------------------------------------------------------------------------------- /app/templates/users/index.hbs: -------------------------------------------------------------------------------- 1 |

All users

2 | 3 |
4 | {{page-numbers content=model numPagesToShow=4}} 5 |
6 | 17 |
18 | {{page-numbers content=content numPagesToShow=4}} 19 | -------------------------------------------------------------------------------- /app/templates/users/new.hbs: -------------------------------------------------------------------------------- 1 |

Sign up

2 | 3 |
4 |
5 | 6 | {{#if errors.messages}} 7 |
8 |
9 | The form contains {{errors.messages.length}} errors. 10 |
11 | {{#each error in errors.messages}} 12 |
    13 |
  • {{error.attribute}} {{error.message}}
  • 14 |
15 | {{/each}} 16 |
17 | {{/if}} 18 | 19 |
20 | 21 | {{input class="form-control" type="text" id="user_name" value=name size="50"}} 22 | 23 | 24 | {{input class="form-control" type="email" id="user_email" value=email size="50"}} 25 | 26 | 27 | {{input class="form-control" type="password" id="user_password" value=password size="50"}} 28 | 29 | 30 | {{input class="form-control" type="password" id="user_password_confirmation" value=passwordConfirmation size="50"}} 31 | 32 | 33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /app/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/app/views/.gitkeep -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rails-tutorial-ember", 3 | "dependencies": { 4 | "handlebars": "~1.3.0", 5 | "jquery": "^1.11.1", 6 | "ember": "1.8.1", 7 | "ember-data": "1.0.0-beta.14.1", 8 | "ember-resolver": "~0.1.10", 9 | "loader.js": "ember-cli/loader.js#1.0.1", 10 | "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", 11 | "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4", 12 | "ember-load-initializers": "ember-cli/ember-load-initializers#0.0.2", 13 | "ember-qunit": "0.1.8", 14 | "ember-qunit-notifications": "0.0.4", 15 | "qunit": "~1.15.0", 16 | "ember-addons.bs_for_ember": "~0.7.0", 17 | "bootstrap-sass-official": "~3.3.1", 18 | "JavaScript-MD5": "~1.1.0", 19 | "ember-simple-auth": "0.7.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | module.exports = function(environment) { 4 | var ENV = { 5 | modulePrefix: 'rails-tutorial-ember', 6 | environment: environment, 7 | baseURL: '/', 8 | locationType: 'auto', 9 | EmberENV: { 10 | FEATURES: { 11 | // Here you can enable experimental features on an ember canary build 12 | // e.g. 'with-controller': true 13 | } 14 | }, 15 | 16 | APP: { 17 | // Here you can pass flags/options to your application instance 18 | // when it is created 19 | }, 20 | 'simple-auth': { 21 | authorizer: 'simple-auth-authorizer:devise', 22 | crossOriginWhitelist: ['*'] 23 | }, 24 | 'simple-auth-devise': { 25 | serverTokenEndpoint: 'http://localhost:3000/api/v1/sessions', 26 | tokenAttributeName: 'token', 27 | identificationAttributeName: 'email' 28 | } 29 | }; 30 | 31 | if (environment === 'development') { 32 | ENV.APP.SERVER_URL = 'http://localhost:3000'; 33 | // ENV.APP.LOG_RESOLVER = true; 34 | ENV.APP.LOG_ACTIVE_GENERATION = true; 35 | // ENV.APP.LOG_TRANSITIONS = true; 36 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 37 | ENV.APP.LOG_VIEW_LOOKUPS = true; 38 | ENV.contentSecurityPolicy = { 39 | 'connect-src': "'self' 'unsafe-eval' http://*:3000", 40 | 'style-src': "'self'", 41 | 'script-src': "'self' 'unsafe-eval' http://*:3000", 42 | 'img-src': "'self' https://www.gravatar.com http://www.gravatar.com http://*:3000 " + 43 | "https://pbs.twimg.com/profile_images/2326095089/3s1seyc0csl75btyw1vl.png" 44 | } 45 | 46 | } 47 | 48 | if (environment === 'test') { 49 | // Testem prefers this... 50 | ENV.baseURL = '/'; 51 | ENV.locationType = 'none'; 52 | 53 | // keep test console output quieter 54 | ENV.APP.LOG_ACTIVE_GENERATION = false; 55 | ENV.APP.LOG_VIEW_LOOKUPS = false; 56 | 57 | ENV.APP.rootElement = '#ember-testing'; 58 | 59 | } 60 | 61 | if (environment === 'production') { 62 | 63 | ENV.APP.SERVER_URL = 'https://rails-tutorial-api.herokuapp.com'; 64 | ENV['simple-auth-devise'] = { 65 | serverTokenEndpoint: 'https://rails-tutorial-api.herokuapp.com/api/v1/sessions', 66 | tokenAttributeName: 'token', 67 | identificationAttributeName: 'email' 68 | } 69 | } 70 | 71 | return ENV; 72 | }; 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rails-tutorial-ember", 3 | "version": "0.0.0", 4 | "private": true, 5 | "directories": { 6 | "doc": "doc", 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "start": "ember server", 11 | "build": "ember build", 12 | "test": "ember test" 13 | }, 14 | "repository": "", 15 | "engines": { 16 | "node": " 0.10.33" 17 | }, 18 | "author": "", 19 | "license": "MIT", 20 | "dependencies": { 21 | "broccoli-asset-rev": "^1.0.0", 22 | "broccoli-ember-hbs-template-compiler": "^1.6.1", 23 | "broccoli-merge-trees": "^0.2.1", 24 | "broccoli-sass": "^0.3.3", 25 | "broccoli-static-compiler": "^0.2.1", 26 | "ember-cli": "0.1.7", 27 | "ember-cli-6to5": "^0.2.1", 28 | "ember-cli-content-security-policy": "0.3.0", 29 | "ember-cli-dependency-checker": "0.0.6", 30 | "ember-cli-gravatar": "1.6.0", 31 | "ember-cli-ic-ajax": "0.1.1", 32 | "ember-cli-inject-live-reload": "^1.3.0", 33 | "ember-cli-pagination": "^0.6.3", 34 | "ember-cli-qunit": "0.1.2", 35 | "ember-cli-simple-auth": "0.7.2", 36 | "ember-cli-simple-auth-devise": "0.7.2", 37 | "ember-data": "^1.0.0-beta.14.1", 38 | "ember-devtools": "^2.1.0", 39 | "ember-export-application-global": "^1.0.0", 40 | "ember-notify": "^3.0.10", 41 | "express": "^4.8.5", 42 | "glob": "^4.0.5" 43 | }, 44 | "devDependencies": { 45 | "broccoli-asset-rev": "^1.0.0", 46 | "broccoli-ember-hbs-template-compiler": "^1.6.1", 47 | "broccoli-merge-trees": "^0.2.1", 48 | "broccoli-sass": "^0.3.3", 49 | "broccoli-static-compiler": "^0.2.1", 50 | "ember-cli": "0.1.7", 51 | "ember-cli-6to5": "^0.2.1", 52 | "ember-cli-content-security-policy": "0.3.0", 53 | "ember-cli-dependency-checker": "0.0.6", 54 | "ember-cli-gravatar": "1.6.0", 55 | "ember-cli-ic-ajax": "0.1.1", 56 | "ember-cli-inject-live-reload": "^1.3.0", 57 | "ember-cli-pagination": "^0.6.3", 58 | "ember-cli-qunit": "0.1.2", 59 | "ember-cli-simple-auth": "0.7.2", 60 | "ember-cli-simple-auth-devise": "0.7.2", 61 | "ember-data": "^1.0.0-beta.14.1", 62 | "ember-devtools": "^2.1.0", 63 | "ember-export-application-global": "^1.0.0", 64 | "ember-notify": "^3.0.10", 65 | "express": "^4.8.5", 66 | "glob": "^4.0.5" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/public/.gitkeep -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "framework": "qunit", 3 | "test_page": "tests/index.html", 4 | "launch_in_ci": [ 5 | "PhantomJS" 6 | ], 7 | "launch_in_dev": [ 8 | "PhantomJS", 9 | "Chrome" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "QUnit", 10 | "define", 11 | "console", 12 | "equal", 13 | "notEqual", 14 | "notStrictEqual", 15 | "test", 16 | "asyncTest", 17 | "testBoth", 18 | "testWithDefault", 19 | "raises", 20 | "throws", 21 | "deepEqual", 22 | "start", 23 | "stop", 24 | "ok", 25 | "strictEqual", 26 | "module", 27 | "moduleFor", 28 | "moduleForComponent", 29 | "moduleForModel", 30 | "process", 31 | "expect", 32 | "visit", 33 | "exists", 34 | "fillIn", 35 | "click", 36 | "keyEvent", 37 | "triggerEvent", 38 | "find", 39 | "findWithAssert", 40 | "wait", 41 | "DS", 42 | "isolatedContainer", 43 | "startApp", 44 | "andThen", 45 | "currentURL", 46 | "currentPath", 47 | "currentRouteName" 48 | ], 49 | "node": false, 50 | "browser": false, 51 | "boss": true, 52 | "curly": false, 53 | "debug": false, 54 | "devel": false, 55 | "eqeqeq": true, 56 | "evil": true, 57 | "forin": false, 58 | "immed": false, 59 | "laxbreak": false, 60 | "newcap": true, 61 | "noarg": true, 62 | "noempty": false, 63 | "nonew": false, 64 | "nomen": false, 65 | "onevar": false, 66 | "plusplus": false, 67 | "regexp": false, 68 | "undef": true, 69 | "sub": true, 70 | "strict": false, 71 | "white": false, 72 | "eqnull": true, 73 | "esnext": true 74 | } 75 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember/resolver'; 2 | import config from '../../config/environment'; 3 | 4 | var resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Application from '../../app'; 3 | import Router from '../../router'; 4 | import config from '../../config/environment'; 5 | 6 | export default function startApp(attrs) { 7 | var App; 8 | 9 | var attributes = Ember.merge({}, config.APP); 10 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 11 | 12 | Ember.run(function() { 13 | App = Application.create(attributes); 14 | App.setupForTesting(); 15 | App.injectTestHelpers(); 16 | }); 17 | 18 | return App; 19 | } 20 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RailsTutorialEmber Tests 7 | 8 | 9 | 10 | {{content-for 'head'}} 11 | {{content-for 'test-head'}} 12 | 13 | 14 | 15 | 16 | 32 | 33 | {{content-for 'head-footer'}} 34 | {{content-for 'test-head-footer'}} 35 | 36 | 37 | 38 | {{content-for 'body'}} 39 | {{content-for 'test-body'}} 40 | 41 | 42 | 43 | 44 | 45 | 46 | {{content-for 'body-footer'}} 47 | {{content-for 'test-body-footer'}} 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import { 3 | setResolver 4 | } from 'ember-qunit'; 5 | 6 | setResolver(resolver); 7 | 8 | document.write('
'); 9 | 10 | QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'}); 11 | var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible'; 12 | document.getElementById('ember-testing-container').style.visibility = containerVisibility; 13 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/tests/unit/.gitkeep -------------------------------------------------------------------------------- /tests/unit/adapters/application-test.js: -------------------------------------------------------------------------------- 1 | import { 2 | moduleFor, 3 | test 4 | } from 'ember-qunit'; 5 | 6 | moduleFor('adapter:application', 'ApplicationAdapter', { 7 | // Specify the other units that are required for this test. 8 | // needs: ['serializer:foo'] 9 | }); 10 | 11 | // Replace this with your real tests. 12 | test('it exists', function() { 13 | var adapter = this.subject(); 14 | ok(adapter); 15 | }); 16 | -------------------------------------------------------------------------------- /tests/unit/components/microposts-index-test.js: -------------------------------------------------------------------------------- 1 | import { 2 | moduleForComponent, 3 | test 4 | } from 'ember-qunit'; 5 | 6 | moduleForComponent('microposts-index', 'MicropostsIndexComponent', { 7 | // specify the other units that are required for this test 8 | // needs: ['component:foo', 'helper:bar'] 9 | }); 10 | 11 | test('it renders', function() { 12 | expect(2); 13 | 14 | // creates the component instance 15 | var component = this.subject(); 16 | equal(component._state, 'preRender'); 17 | 18 | // appends the component to the page 19 | this.append(); 20 | equal(component._state, 'inDOM'); 21 | }); 22 | -------------------------------------------------------------------------------- /tests/unit/helpers/time-ago-test.js: -------------------------------------------------------------------------------- 1 | import { 2 | timeAgo 3 | } from 'rails-tutorial-ember/helpers/time-ago'; 4 | 5 | module('TimeAgoHelper'); 6 | 7 | // Replace this with your real tests. 8 | test('it works', function() { 9 | var result = timeAgo(42); 10 | ok(result); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/unit/initializers/custom-session-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import { initialize } from 'rails-tutorial-ember/initializers/custom-session'; 3 | 4 | var container, application; 5 | 6 | module('CustomSessionInitializer', { 7 | setup: function() { 8 | Ember.run(function() { 9 | application = Ember.Application.create(); 10 | container = application.__container__; 11 | application.deferReadiness(); 12 | }); 13 | } 14 | }); 15 | 16 | // Replace this with your real tests. 17 | test('it works', function() { 18 | initialize(container, application); 19 | 20 | // you would normally confirm the results of the initializer here 21 | ok(true); 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/rails_tutorial_ember/c57b0a9ef562348316e2abc12707345c74864d3e/vendor/.gitkeep --------------------------------------------------------------------------------