├── .bowerrc ├── .editorconfig ├── .ember-cli ├── .gitignore ├── .jshintrc ├── .watchmanconfig ├── README.md ├── app ├── adapters │ └── application.js ├── app.js ├── authenticators │ └── devise.js ├── authorizers │ └── devise.js ├── components │ └── .gitkeep ├── controllers │ └── .gitkeep ├── helpers │ ├── .gitkeep │ ├── humanize.js │ └── pluralize.js ├── index.html ├── initializers │ └── inject-session.js ├── mixins │ └── reset-scroll.js ├── models │ ├── .gitkeep │ ├── feed.js │ ├── micropost.js │ ├── person.js │ ├── session.js │ └── user.js ├── pods │ ├── application │ │ ├── route.js │ │ └── template.hbs │ ├── components │ │ ├── follow-form │ │ │ └── template.hbs │ │ ├── microposts-index │ │ │ └── template.hbs │ │ ├── resource-errors │ │ │ └── template.hbs │ │ ├── user-aside │ │ │ └── template.hbs │ │ ├── user-form │ │ │ └── template.hbs │ │ ├── user-profile │ │ │ └── template.hbs │ │ ├── user-stats │ │ │ └── template.hbs │ │ └── users-list │ │ │ └── template.hbs │ ├── contact │ │ └── template.hbs │ ├── help │ │ └── template.hbs │ ├── index │ │ ├── route.js │ │ └── template.hbs │ ├── sessions │ │ └── new │ │ │ ├── route.js │ │ │ └── template.hbs │ ├── user │ │ ├── edit │ │ │ ├── route.js │ │ │ └── template.hbs │ │ ├── followers │ │ │ ├── route.js │ │ │ └── template.hbs │ │ ├── following │ │ │ ├── route.js │ │ │ └── template.hbs │ │ ├── index │ │ │ ├── route.js │ │ │ └── template.hbs │ │ └── route.js │ └── users │ │ ├── activation │ │ ├── route.js │ │ └── template.hbs │ │ ├── new │ │ ├── route.js │ │ └── template.hbs │ │ ├── route.js │ │ └── template.hbs ├── resolver.js ├── router.js ├── routes │ └── .gitkeep ├── serializers │ └── application.js ├── styles │ └── app.scss ├── templates │ └── components │ │ └── .gitkeep └── transforms │ └── moment.js ├── bower.json ├── config └── environment.js ├── ember-cli-build.js ├── package.json ├── public ├── crossdomain.xml └── robots.txt ├── testem.js ├── tests ├── .jshintrc ├── helpers │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ └── start-app.js ├── index.html ├── integration │ └── .gitkeep ├── test-helper.js └── unit │ └── .gitkeep └── 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 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.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 | .envrc 19 | -------------------------------------------------------------------------------- /.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 | "esversion": 6, 31 | "unused": true 32 | } 33 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ember-on-rails5 2 | 3 | Michael Hart's Rails tutorial.. on Ember! Check the rails 5 [backend API](https://github.com/vasilakisfil/rails5_api_tutorial). Deployed [here](https://ember-on-rails5.herokuapp.com) The tutoral is on its way... 4 | 5 | ## Prerequisites 6 | 7 | You will need the following things properly installed on your computer. 8 | 9 | * [Git](http://git-scm.com/) 10 | * [Node.js](http://nodejs.org/) (with NPM) 11 | * [Bower](http://bower.io/) 12 | * [Ember CLI](http://ember-cli.com/) 13 | * [PhantomJS](http://phantomjs.org/) 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 serve` 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://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 JSONAPIAdapter from 'ember-data/adapters/json-api'; 2 | import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin'; 3 | import ENV from 'ember-on-rails5/config/environment'; 4 | import HasManyQuery from 'ember-data-has-many-query'; 5 | 6 | 7 | export default JSONAPIAdapter.extend(DataAdapterMixin, HasManyQuery.RESTAdapterMixin, { 8 | host: ENV.APP.API_HOST, 9 | namespace: ENV.APP.API_NAMESPACE, 10 | authorizer: 'authorizer:devise' 11 | }); 12 | 13 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | let App; 7 | 8 | Ember.MODEL_FACTORY_INJECTIONS = true; 9 | 10 | App = Ember.Application.extend({ 11 | modulePrefix: config.modulePrefix, 12 | podModulePrefix: config.podModulePrefix, 13 | Resolver 14 | }); 15 | 16 | loadInitializers(App, config.modulePrefix); 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /app/authenticators/devise.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Devise from 'ember-simple-auth/authenticators/devise'; 3 | const { RSVP: { Promise }, run } = Ember; 4 | 5 | export default Devise.extend({ 6 | store: Ember.inject.service('store'), 7 | tokenAttributeName: 'token', 8 | identificationAttributeName: 'email', 9 | 10 | //check how Samuel's solution on Valu8 11 | authenticate(identification, password) { 12 | return new Promise((resolve, reject) => { 13 | var data = { 14 | password: password, 15 | [this.get('identificationAttributeName')]: identification 16 | }; 17 | 18 | return this.makeRequest(data).then( 19 | (response) => { 20 | response = this.get('store').serializerFor('application').removeEmptyData(response); 21 | this.get('store').pushPayload(response); //too bad that pushPayload returns nothing 22 | var record = this.get('store').peekRecord('session', response.data.id); 23 | run(null, resolve, record.toJSON({includeId: true})); 24 | }, 25 | (xhr) => { 26 | run(null, reject, xhr.errors.get('firstObject.title')); 27 | } 28 | ); 29 | }); 30 | }, 31 | 32 | makeRequest(data) { 33 | return this.get('store').adapterFor('session').ajax( 34 | this.get('store').adapterFor('session').buildURL('session'), 35 | "POST", 36 | { 37 | data: 38 | { 39 | data: { 40 | attributes: data 41 | } 42 | } 43 | } 44 | ); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /app/authorizers/devise.js: -------------------------------------------------------------------------------- 1 | import Devise from 'ember-simple-auth/authorizers/devise'; 2 | 3 | export default Devise.extend({ 4 | serverTokenEndpoint: 'http://localhost:3000/api/v1/sessions' 5 | }); 6 | -------------------------------------------------------------------------------- /app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/components/.gitkeep -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/controllers/.gitkeep -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/helpers/.gitkeep -------------------------------------------------------------------------------- /app/helpers/humanize.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export function humanize([word]) { 4 | return word.decamelize().split('_').join(' ').capitalize(); 5 | } 6 | 7 | export default Ember.Helper.helper(humanize); 8 | -------------------------------------------------------------------------------- /app/helpers/pluralize.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export function pluralize(params) { 4 | let [word, amount] = params; 5 | var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); 6 | 7 | if (amount > 1) { 8 | return inflector.pluralize(word); 9 | } else { 10 | return inflector.singularize(word); 11 | } 12 | } 13 | 14 | export default Ember.Helper.helper(pluralize); 15 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EmberOnRails5 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/inject-session.js: -------------------------------------------------------------------------------- 1 | export function initialize(application) { 2 | application.inject('route', 'session', 'service:session'); 3 | application.inject('controller', 'session', 'service:session'); 4 | application.inject('component', 'session', 'service:session'); 5 | } 6 | 7 | export default { 8 | after: 'store', 9 | name: 'inject-session', 10 | initialize: initialize 11 | }; 12 | -------------------------------------------------------------------------------- /app/mixins/reset-scroll.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Mixin.create({ 4 | didTransition() { 5 | this._super(); 6 | 7 | this._scrollUp(); 8 | }, 9 | 10 | _scrollUp() { 11 | window.scrollTo(0,0); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/feed.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/models/feed.js -------------------------------------------------------------------------------- /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 | userId: DS.attr('string'), 7 | 8 | createdAt: DS.attr('moment'), 9 | updatedAt: DS.attr('moment'), 10 | 11 | user: DS.belongsTo('user', {async: true, inverse: 'microposts'}), 12 | 13 | pictureUrl: function() { 14 | return 'http://localhost:3000/' + this.get('picture'); 15 | }.property('picture') 16 | }); 17 | -------------------------------------------------------------------------------- /app/models/person.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import DS from 'ember-data'; 3 | 4 | export default DS.Model.extend({ 5 | email: DS.attr('string'), 6 | name: DS.attr('string'), 7 | 8 | admin: DS.attr('boolean'), 9 | 10 | followerState: DS.attr('boolean'), 11 | followingState: DS.attr('boolean'), 12 | 13 | micropostsCount: DS.attr('number'), 14 | followersCount: DS.attr('number'), 15 | followingsCount: DS.attr('number'), 16 | 17 | createdAt: DS.attr('moment'), 18 | updatedAt: DS.attr('moment'), 19 | 20 | microposts: DS.hasMany('micropost', {async: true}), 21 | feed: DS.hasMany('micropost', {async: true}), 22 | followers: DS.hasMany('person'), 23 | followings: DS.hasMany('person'), 24 | 25 | isFollower: Ember.computed.oneWay('followerState'), 26 | isFollowed: Ember.computed.oneWay('followingState'), 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /app/models/session.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.Model.extend({ 4 | userId: DS.attr('string'), 5 | email: DS.attr('string'), 6 | token: DS.attr('string'), 7 | 8 | user: DS.belongsTo('user') 9 | }); 10 | -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | import HasManyQuery from 'ember-data-has-many-query'; 3 | import Person from './person'; 4 | 5 | export default Person.extend(HasManyQuery.ModelMixin, { 6 | password: DS.attr('string'), 7 | 8 | valid() { 9 | if (!this.get('password')) { return true; } 10 | 11 | this.get('errors')._clear(); 12 | 13 | if (this.get('password') === this.get('passwordConfirmation')) { return true;} 14 | 15 | this.get('errors')._add('passwordConfirmation', 'is not the same with the password'); 16 | return false; 17 | }, 18 | 19 | clean() { 20 | this.setProperties({ 21 | password: null, 22 | passwordConfirmation: null 23 | }); 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /app/pods/application/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin'; 3 | 4 | export default Ember.Route.extend(ApplicationRouteMixin, { 5 | notify: Ember.inject.service('notify'), 6 | 7 | afterModel() { 8 | if(this.get('session.isAuthenticated')) { 9 | let userId = this.get('session.data.authenticated.userId'); 10 | 11 | if(this.get('store').hasRecordForId('user', userId)) { 12 | this._loadCurrentUser(); 13 | } else { 14 | return this._fetchCurrentUser(); 15 | } 16 | } else { 17 | this.set('session.currentUser', null); 18 | } 19 | }, 20 | 21 | actions: { 22 | createSession(session) { 23 | this.get('session').authenticate( 24 | 'authenticator:devise', 25 | session.get('identifier'), 26 | session.get('password') 27 | ).then( 28 | () => { 29 | this.get('notify').success('You are in!'); 30 | this._loadCurrentUser(); 31 | this.controllerFor('sessions.new').set('loginError', null); 32 | }, 33 | (reason) => this.controllerFor('sessions.new').set('loginError', reason) 34 | ); 35 | }, 36 | destroySession() { 37 | this.get('session').invalidate(); 38 | }, 39 | getPage(page) { 40 | this.transitionTo({ queryParams: { page }}); 41 | } 42 | }, 43 | 44 | _loadCurrentUser() { 45 | this.set( 46 | 'session.currentUser', 47 | this.get('store').peekRecord( 48 | 'user', this.get('session.data.authenticated.userId') 49 | ) 50 | ); 51 | }, 52 | 53 | _fetchCurrentUser() { 54 | var userId = this.get('session.data.authenticated.userId'); 55 | var _this = this; 56 | 57 | return this.get('store').findRecord('user', userId).then(function(user) { 58 | _this.set('session.currentUser', user); 59 | }); 60 | }, 61 | 62 | }); 63 | -------------------------------------------------------------------------------- /app/pods/application/template.hbs: -------------------------------------------------------------------------------- 1 | 30 |
31 | {{ember-notify closeAfter=4000 messageStyle='bootstrap'}} 32 | 33 | {{outlet}} 34 | 35 | 49 |
50 | -------------------------------------------------------------------------------- /app/pods/components/follow-form/template.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{#if model.isFollowed}} 4 | 5 | {{else}} 6 | 7 | {{/if}} 8 |
9 |
10 | -------------------------------------------------------------------------------- /app/pods/components/microposts-index/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if title}} 2 |

{{title}}

3 | {{else}} 4 | {{#if model.length}} 5 |

Microposts ({{micropostsCount}})

6 | {{/if}} 7 | {{/if}} 8 | {{#if model}} 9 |
    10 | {{#each model as |micropost|}} 11 |
  1. 12 | {{gravatar-image email=micropost.user.email alt=micropost.user.name size=50 class='gravatar'}} 13 | 14 | {{link-to micropost.user.name 'user.index' micropost.user}} 15 | 16 | {{! here .content delegates to the proxy object content/model}} 17 | {{micropost.content}} 18 | 19 | 20 | Posted about {{moment-from-now micropost.createdAt interval=10000}}. 21 | {{#if micropost.isAuthor}} 22 | delete 23 | {{/if}} 24 | 25 |
  2. 26 | 27 | {{/each}} 28 |
29 | 30 | {{simple-pagination 31 | recordCount=meta.total-count 32 | pageSize=25 33 | pageNumber=meta.current-page 34 | maxPagesInList=10 35 | onPageSelect=(route-action "getPage")}} 36 | {{/if}} 37 | -------------------------------------------------------------------------------- /app/pods/components/resource-errors/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if errors}} 2 |
3 |
4 | The form contains {{errors.length}} {{pluralize 'error' amount=1}}. 5 |
6 | 11 |
12 | {{/if}} 13 | -------------------------------------------------------------------------------- /app/pods/components/user-aside/template.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#link-to 'user.index' model}} 3 | {{gravatar-image email=model.email alt=model.name size=80 class='gravatar'}} 4 | {{/link-to}} 5 |

{{model.name}}

6 | {{#unless profileRoute}} 7 | {{#if (eq model.id currentUserId)}} 8 | {{link-to "View my profile" 'user.index' model}} 9 | {{else}} 10 | {{link-to "View profile" 'user.index' model}} 11 | {{/if}} 12 | {{/unless}} 13 | {{model.micropostsCount}} {{pluralize "micropost" model.micropostsCount}} 14 |
15 |
16 | {{user-stats model=model class="stats"}} 17 |
18 | -------------------------------------------------------------------------------- /app/pods/components/user-form/template.hbs: -------------------------------------------------------------------------------- 1 | {{resource-errors errors=model.errors}} 2 | 3 |
4 | 5 | {{input class="form-control" type="text" value=model.name id="user_name"}} 6 | 7 | 8 | {{input class="form-control" type="text" value=model.email id="user_email"}} 9 | 10 | 11 | {{input class="form-control" type="password" value=model.password id="user_password"}} 12 | 13 | 14 | {{input class="form-control" type="password" value=model.passwordConfirmation id="user_password_confirmation"}} 15 | 16 | 17 |
18 | -------------------------------------------------------------------------------- /app/pods/components/user-profile/template.hbs: -------------------------------------------------------------------------------- 1 | {{#link-to 'user.index' session.currentUser}} 2 | {{gravatar-image email=model.email alt=model.name size=80 class='gravatar' size=50}} 3 | {{/link-to}} 4 |

{{model.name}}

5 | {{link-to "View my profile" 'user.index' model}} 6 | {{model.micropostsCount}} {{pluralize "micropost" model.micropostsCount}} 7 | -------------------------------------------------------------------------------- /app/pods/components/user-stats/template.hbs: -------------------------------------------------------------------------------- 1 | {{#link-to 'user.following' model.id}} 2 | 3 | {{model.followingsCount}} 4 | 5 | following 6 | {{/link-to}} 7 | 8 | {{#link-to 'user.followers' model.id}} 9 | 10 | {{model.followersCount}} 11 | 12 | followers 13 | {{/link-to}} 14 | -------------------------------------------------------------------------------- /app/pods/components/users-list/template.hbs: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /app/pods/contact/template.hbs: -------------------------------------------------------------------------------- 1 |

Contact

2 |

3 | Open a gihub issue in the repositories 4 | ember_on_rails5 and rails5_api_tutorial. 5 |

6 | -------------------------------------------------------------------------------- /app/pods/help/template.hbs: -------------------------------------------------------------------------------- 1 |

Help

2 |

3 | Open a gihub issue in the repositories 4 | ember_on_rails5 and rails5_api_tutorial. 5 |

6 | -------------------------------------------------------------------------------- /app/pods/index/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ResetScroll from 'ember-on-rails5/mixins/reset-scroll'; 3 | 4 | export default Ember.Route.extend(ResetScroll, { 5 | queryParams: { 6 | page: { 7 | refreshModel: true 8 | } 9 | }, 10 | 11 | model(params) { 12 | if(this.get('session.isAuthenticated')) { 13 | return Ember.RSVP.hash({ 14 | feed: this._fetchFeed(params.page || 1), 15 | micropost: this._newMicropost() 16 | }); 17 | } 18 | }, 19 | 20 | afterModel() { 21 | //transitionTo to the same route does not fire didTransition 22 | this._scrollUp(); 23 | }, 24 | 25 | actions: { 26 | createMicropost(micropost) { 27 | var _this = this; 28 | 29 | micropost.save().then((micropost) => { 30 | _this.controllerFor('index').get('model.feed').unshiftObject(micropost); 31 | _this.controllerFor('index').set('model.micropost', _this._newMicropost()); 32 | }); 33 | } 34 | }, 35 | 36 | _newMicropost() { 37 | return this.get('store').createRecord('micropost', { 38 | user: this.get('session.currentUser') 39 | }); 40 | }, 41 | 42 | _fetchFeed(page = 1) { 43 | return this.get('session.currentUser').query('feed', {page: page}); 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /app/pods/index/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if session.isAuthenticated}} 2 |
3 | 24 |
25 | {{microposts-index 26 | title="Micropost Feed" 27 | model=model.feed 28 | meta=model.feed.meta 29 | }} 30 |
31 |
32 | {{else}} 33 |
34 |

Welcome to the Sample App

35 | 36 |

37 | This is the home page for the 38 | Ember on Rails Tutorial 39 | sample application. 40 |

41 | 42 | {{link-to "Sign up now!" 'users.new' class="btn btn-lg btn-primary"}} 43 |
44 | 45 | 46 | 47 | 48 | {{/if}} 49 | -------------------------------------------------------------------------------- /app/pods/sessions/new/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin'; 3 | 4 | export default Ember.Route.extend(UnauthenticatedRouteMixin, { 5 | model() { 6 | return Ember.Object.create({ 7 | identifier: null, 8 | password: null 9 | }); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /app/pods/sessions/new/template.hbs: -------------------------------------------------------------------------------- 1 |

Log in

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

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

29 |
30 |
31 | -------------------------------------------------------------------------------- /app/pods/user/edit/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | notify: Ember.inject.service('notify'), 5 | 6 | actions: { 7 | updateUser(user) { 8 | if(user.valid()) { 9 | user.save().then( 10 | () => { 11 | user.clean(); 12 | this.get('notify').success('Your profile has been updated!'); 13 | this.transitionTo('index'); 14 | } 15 | ); 16 | } 17 | } 18 | } 19 | }); 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/pods/user/edit/template.hbs: -------------------------------------------------------------------------------- 1 |

Update your profile

2 | 3 |
4 |
5 | 6 | {{user-form 7 | model=model 8 | createOrUpdateUser=(route-action 'updateUser') 9 | submitText="Save changes" 10 | }} 11 |
12 |
13 | -------------------------------------------------------------------------------- /app/pods/user/followers/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | model() { 5 | return Ember.RSVP.hash({ 6 | user: this.modelFor('user'), 7 | followers: this.modelFor('user').get('followers') 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /app/pods/user/followers/template.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{user-aside 3 | model=model.user 4 | currentUserId=session.currentUser.id 5 | tagName="aside" 6 | class="col-md-4" 7 | }} 8 |
9 | {{users-list model=model.followers}} 10 |
11 |
12 | -------------------------------------------------------------------------------- /app/pods/user/following/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | model() { 5 | return Ember.RSVP.hash({ 6 | user: this.modelFor('user'), 7 | followings: this.modelFor('user').get('followings') 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /app/pods/user/following/template.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{user-aside 3 | model=model.user 4 | currentUserId=session.currentUser.id 5 | tagName="aside" 6 | class="col-md-4" 7 | }} 8 |
9 | {{users-list model=model.followings}} 10 |
11 |
12 | -------------------------------------------------------------------------------- /app/pods/user/index/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import ResetScroll from 'ember-on-rails5/mixins/reset-scroll'; 3 | 4 | export default Ember.Route.extend(ResetScroll, { 5 | queryParams: { 6 | page: { 7 | refreshModel: true 8 | } 9 | }, 10 | 11 | model(params) { 12 | return Ember.RSVP.hash({ 13 | user: this.modelFor('user'), 14 | microposts: this._fetchMicroposts(params.page) 15 | }); 16 | }, 17 | 18 | afterModel() { 19 | //transitionTo to the same route does not fire didTransition 20 | this._scrollUp(); 21 | }, 22 | 23 | _fetchMicroposts(page = 1) { 24 | return this.get('store').query('micropost', { 25 | user_id: this.modelFor('user').get('id'), page 26 | }); 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /app/pods/user/index/template.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{user-aside 3 | model=model.user 4 | tagName="aside" 5 | class="col-md-4" 6 | profileRoute=true 7 | }} 8 |
9 | {{#if (not-eq session.currentUser.id model.user.id)}} 10 | {{follow-form model=model.user}} 11 | {{/if}} 12 | {{microposts-index 13 | model=model.microposts 14 | micropostsCount=model.user.micropostsCount 15 | meta=model.microposts.meta 16 | }} 17 |
18 |
19 | -------------------------------------------------------------------------------- /app/pods/user/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | actions: { 5 | followUser(userId) { 6 | this.get('store').adapterFor('application').ajax( 7 | this.get('store').adapterFor('user').buildURL( 8 | 'user', this.get('session.currentUser.id') 9 | ) + '/followings/' + userId, 10 | "POST", 11 | {} 12 | ).then((userData) => this.get('store').pushPayload(userData)); 13 | }, 14 | 15 | unfollowUser(userId) { 16 | this.get('store').adapterFor('application').ajax( 17 | this.get('store').adapterFor('user').buildURL( 18 | 'user', this.get('session.currentUser.id') 19 | ) + '/followings/' + userId, 20 | "DELETE", 21 | {} 22 | ).then((userData) => this.get('store').pushPayload(userData)); 23 | } 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /app/pods/users/activation/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | notify: Ember.inject.service('notify'), 5 | 6 | beforeModel(transition) { 7 | if(Ember.isBlank(transition.queryParams.token) || Ember.isBlank(transition.queryParams.token)) { 8 | this.transitionTo('sessions.new'); 9 | } 10 | this.set('params', transition.queryParams); 11 | }, 12 | 13 | setupController() { 14 | this._super(...arguments); 15 | 16 | let query = `email=${this.get('params').email}&token=${this.get('params').token}`; 17 | 18 | this.get('store').adapterFor('user').ajax( 19 | this.get('store').adapterFor('user').buildURL('users') + `/activate?${query}`, 20 | "POST", 21 | {} 22 | ).then(() => { 23 | this.transitionTo('sessions.new'); 24 | this.get('notify').success('Great! You verified your email and you can now login'); 25 | }, () => { 26 | this.transitionTo('application'); 27 | this.get('notify').error('Activation link is invalid'); 28 | }); 29 | } 30 | }); 31 | 32 | -------------------------------------------------------------------------------- /app/pods/users/activation/template.hbs: -------------------------------------------------------------------------------- 1 | {{ember-spinner}} 2 | -------------------------------------------------------------------------------- /app/pods/users/new/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | notify: Ember.inject.service('notify'), 5 | 6 | model() { 7 | return this.get('store').createRecord('user', {}); 8 | }, 9 | 10 | actions: { 11 | createUser(user) { 12 | if (!user.valid()) { return false; } 13 | 14 | user.save().then( 15 | () => { 16 | /* 17 | this.get('notify').success('Please check your email to activate your account', { 18 | closeAfter: 10000 19 | }); 20 | */ 21 | this.get('notify').success('You can now sign in!', {closeAfter: 10000}); 22 | this.get('notify').success( 23 | 'Activation emails have been disabled for the demo, your account is automatically activated', { 24 | closeAfter: 10000 25 | }); 26 | 27 | this.transitionTo('index'); 28 | } 29 | ); 30 | } 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /app/pods/users/new/template.hbs: -------------------------------------------------------------------------------- 1 |

Sign up

2 | 3 |
4 |
5 | 6 | {{user-form 7 | model=model 8 | createOrUpdateUser=(route-action 'createUser') 9 | submitText="Create my account" 10 | }} 11 |
12 |
13 | -------------------------------------------------------------------------------- /app/pods/users/route.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | model() { 5 | return this.get('store').findAll('user'); 6 | } 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /app/pods/users/template.hbs: -------------------------------------------------------------------------------- 1 |

All users

2 | 3 |
4 | {{!page-numbers content=model numPagesToShow=4}} 5 |
6 | {{users-list model=model}} 7 |
8 | {{!page-numbers content=content numPagesToShow=4}} 9 | -------------------------------------------------------------------------------- /app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from './config/environment'; 3 | 4 | const Router = Ember.Router.extend({ 5 | location: config.locationType, 6 | rootURL: config.rootURL 7 | }); 8 | 9 | Router.map(function() { 10 | this.route('help'); 11 | this.route('about'); 12 | this.route('contact'); 13 | 14 | this.route('sessions.new', {path: '/login'}); 15 | this.route('users.new', {path: '/signup'}); 16 | this.route('users.activation', {path: '/users/activation'}); 17 | 18 | this.route('users', function() {}); 19 | this.route('user', {path: '/users/:user_id'}, function() { 20 | this.route('edit'); 21 | this.route('following'); 22 | this.route('followers'); 23 | }); 24 | }); 25 | 26 | export default Router; 27 | -------------------------------------------------------------------------------- /app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/routes/.gitkeep -------------------------------------------------------------------------------- /app/serializers/application.js: -------------------------------------------------------------------------------- 1 | import DS from 'ember-data'; 2 | 3 | export default DS.JSONAPISerializer.extend({ 4 | normalizeResponse(store, primaryModelClass, payload, id, requestType) { 5 | this.removeEmptyData(payload); 6 | 7 | return this._super(store, primaryModelClass, payload, id, requestType); 8 | }, 9 | 10 | removeEmptyData(payload) { 11 | var relationships = payload.data.relationships; 12 | 13 | if(relationships) { 14 | Object.keys(relationships).forEach((key) => { 15 | let data = relationships[key].data; 16 | 17 | if(data && this._isNullOrEmptyArray(data)) { 18 | delete relationships[key].data; 19 | } 20 | }); 21 | } 22 | 23 | var includedRel = payload.included || []; 24 | 25 | includedRel.forEach((resource, index, includes) => { 26 | var relationships = resource.relationships; 27 | 28 | if(relationships) { 29 | Object.keys(relationships).forEach((key) => { 30 | let data = relationships[key].data; 31 | 32 | if(data && this._isNullOrEmptyArray(data)) { 33 | delete relationships[key].data; 34 | } 35 | }); 36 | } 37 | 38 | includes[index] = resource; 39 | }); 40 | 41 | return payload; 42 | }, 43 | 44 | serializeAttribute(snapshot, json, key, attributes) { 45 | if (snapshot.record.get('isNew') || snapshot.changedAttributes()[key]) { 46 | this._super(snapshot, json, key, attributes); 47 | } 48 | }, 49 | 50 | _isNullOrEmptyArray(value) { 51 | return (value === null || value === undefined || value.length === 0); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "ember-bootstrap/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/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/app/templates/components/.gitkeep -------------------------------------------------------------------------------- /app/transforms/moment.js: -------------------------------------------------------------------------------- 1 | import DS from "ember-data"; 2 | import moment from 'moment'; 3 | 4 | export default DS.Transform.extend({ 5 | serialize: function(value) { 6 | return value ? moment(value).utc().toJSON() : null; 7 | }, 8 | 9 | deserialize: function(value) { 10 | return value ? moment(value) : null; 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-on-rails5", 3 | "dependencies": { 4 | "ember": "2.9.1", 5 | "ember-cli-shims": "0.1.1", 6 | "ember-qunit-notifications": "0.1.0", 7 | "blueimp-md5": "2.1.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | module.exports = function(environment) { 4 | var ENV = { 5 | modulePrefix: 'ember-on-rails5', 6 | podModulePrefix: 'ember-on-rails5/pods', 7 | environment: environment, 8 | rootURL: '/', 9 | locationType: 'auto', 10 | EmberENV: { 11 | FEATURES: { 12 | // Here you can enable experimental features on an ember canary build 13 | // e.g. 'with-controller': true 14 | } 15 | }, 16 | 17 | APP: { 18 | // Here you can pass flags/options to your application instance 19 | // when it is created 20 | }, 21 | 'ember-devtools': { 22 | global: true, 23 | enabled: environment === 'development' 24 | }, 25 | 'ember-simple-auth': { 26 | authenticationRoute: 'sessions.new', 27 | routeAfterAuthentication: 'index', 28 | routeIfAlreadyAuthenticated: 'index' 29 | }, 30 | }; 31 | 32 | if (environment === 'development') { 33 | ENV.APP.API_HOST = process.env.API_HOST; 34 | ENV.APP.API_NAMESPACE = process.env.API_NAMESPACE; 35 | } 36 | 37 | if (environment === 'test') { 38 | // Testem prefers this... 39 | ENV.locationType = 'none'; 40 | 41 | // keep test console output quieter 42 | ENV.APP.LOG_ACTIVE_GENERATION = false; 43 | ENV.APP.LOG_VIEW_LOOKUPS = false; 44 | 45 | ENV.APP.rootElement = '#ember-testing'; 46 | } 47 | 48 | if (environment === 'production') { 49 | ENV.APP.API_HOST = process.env.API_HOST; 50 | ENV.APP.API_NAMESPACE = process.env.API_NAMESPACE; 51 | } 52 | 53 | return ENV; 54 | }; 55 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | /* global require, module */ 3 | var EmberApp = require('ember-cli/lib/broccoli/ember-app'); 4 | 5 | module.exports = function(defaults) { 6 | var app = new EmberApp(defaults, { 7 | 'ember-cli-bootstrap-sassy': { 8 | 'js': false 9 | }, 10 | 'ember-bootstrap': { 11 | importBootstrapCSS: false, 12 | importBootstrapFont: false 13 | } 14 | }); 15 | 16 | // Use `app.import` to add additional libraries to the generated 17 | // output files. 18 | // 19 | // If you need to use different assets in different 20 | // environments, specify an object as the first parameter. That 21 | // object's keys should be the environment name and the values 22 | // should be the asset to use in that environment. 23 | // 24 | // If the library that you are including contains AMD or ES6 25 | // modules that you would like to import into your application 26 | // please specify an object with the list of modules as keys 27 | // along with the exports of each module as its value. 28 | 29 | return app.toTree(); 30 | }; 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-on-rails5", 3 | "version": "0.0.0", 4 | "description": "Small description for ember-on-rails5 goes here", 5 | "private": true, 6 | "directories": { 7 | "doc": "doc", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "build": "ember build", 12 | "start": "ember server", 13 | "test": "ember test" 14 | }, 15 | "repository": "", 16 | "engines": { 17 | "node": ">= 0.10.0" 18 | }, 19 | "author": "", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "bootstrap-sass": "^3.3.7", 23 | "broccoli-asset-rev": "^2.4.2", 24 | "ember-ajax": "^2.0.1", 25 | "ember-bootstrap": "1.0.0-alpha.4", 26 | "ember-cli": "2.7.0", 27 | "ember-cli-app-version": "^1.0.0", 28 | "ember-cli-babel": "^5.1.6", 29 | "ember-cli-dependency-checker": "^1.2.0", 30 | "ember-cli-gravatar": "3.6.0", 31 | "ember-cli-htmlbars": "^1.0.3", 32 | "ember-cli-htmlbars-inline-precompile": "^0.3.1", 33 | "ember-cli-inject-live-reload": "^1.4.0", 34 | "ember-cli-jshint": "^1.0.0", 35 | "ember-cli-moment-shim": "2.0.0", 36 | "ember-cli-qunit": "^2.0.0", 37 | "ember-cli-release": "^0.2.9", 38 | "ember-cli-sass": "5.5.1", 39 | "ember-cli-sri": "^2.1.0", 40 | "ember-cli-test-loader": "^1.1.0", 41 | "ember-cli-uglify": "^1.2.0", 42 | "ember-data": "^2.7.0", 43 | "ember-data-has-many-query": "0.1.7", 44 | "ember-devtools": "^5.0.1", 45 | "ember-export-application-global": "^1.0.5", 46 | "ember-load-initializers": "^0.5.1", 47 | "ember-moment": "7.0.0-beta.3", 48 | "ember-notify": "^5.1.0", 49 | "ember-resolver": "^2.0.3", 50 | "ember-route-action-helper": "1.0.0", 51 | "ember-simple-auth": "1.1.0", 52 | "ember-simple-pagination": "0.1.0", 53 | "ember-truth-helpers": "1.2.0", 54 | "ember-welcome-page": "^1.0.1", 55 | "loader.js": "^4.0.1" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /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 | Disallow: 4 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | module.exports = { 3 | "framework": "qunit", 4 | "test_page": "tests/index.html?hidepassed", 5 | "disable_watching": true, 6 | "launch_in_ci": [ 7 | "PhantomJS" 8 | ], 9 | "launch_in_dev": [ 10 | "PhantomJS", 11 | "Chrome" 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "define", 10 | "console", 11 | "visit", 12 | "exists", 13 | "fillIn", 14 | "click", 15 | "keyEvent", 16 | "triggerEvent", 17 | "find", 18 | "findWithAssert", 19 | "wait", 20 | "DS", 21 | "andThen", 22 | "currentURL", 23 | "currentPath", 24 | "currentRouteName" 25 | ], 26 | "node": false, 27 | "browser": false, 28 | "boss": true, 29 | "curly": true, 30 | "debug": false, 31 | "devel": false, 32 | "eqeqeq": true, 33 | "evil": true, 34 | "forin": false, 35 | "immed": false, 36 | "laxbreak": false, 37 | "newcap": true, 38 | "noarg": true, 39 | "noempty": false, 40 | "nonew": false, 41 | "nomen": false, 42 | "onevar": false, 43 | "plusplus": false, 44 | "regexp": false, 45 | "undef": true, 46 | "sub": true, 47 | "strict": false, 48 | "white": false, 49 | "eqnull": true, 50 | "esversion": 6, 51 | "unused": true 52 | } 53 | -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default function destroyApp(application) { 4 | Ember.run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { module } from 'qunit'; 2 | import Ember from 'ember'; 3 | import startApp from '../helpers/start-app'; 4 | import destroyApp from '../helpers/destroy-app'; 5 | 6 | const { RSVP: { Promise } } = Ember; 7 | 8 | export default function(name, options = {}) { 9 | module(name, { 10 | beforeEach() { 11 | this.application = startApp(); 12 | 13 | if (options.beforeEach) { 14 | return options.beforeEach.apply(this, arguments); 15 | } 16 | }, 17 | 18 | afterEach() { 19 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments); 20 | return Promise.resolve(afterEach).then(() => destroyApp(this.application)); 21 | } 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const 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 config from '../../config/environment'; 4 | 5 | export default function startApp(attrs) { 6 | let application; 7 | 8 | let attributes = Ember.merge({}, config.APP); 9 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 10 | 11 | Ember.run(() => { 12 | application = Application.create(attributes); 13 | application.setupForTesting(); 14 | application.injectTestHelpers(); 15 | }); 16 | 17 | return application; 18 | } 19 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EmberOnRails5 Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for "body-footer"}} 31 | {{content-for "test-body-footer"}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import { 3 | setResolver 4 | } from 'ember-qunit'; 5 | 6 | setResolver(resolver); 7 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/tests/unit/.gitkeep -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vasilakisfil/ember_on_rails5/f5b97c7fe9caf07fcca2840045ef6602ee076dc9/vendor/.gitkeep --------------------------------------------------------------------------------