-
Notifications
You must be signed in to change notification settings - Fork 16
Model UI
CHANGES This page has been updated for the 9.x
branch.
Legacy instructions are gone - clone this wiki repo and checkout the 8.x
tag.
Define a set of models for our ember app. They will mirror the properties
we have exposed in our serializers, except for the id
(ember will handle
the id
automatically).
models/post.coffee
:
EmberAuthRailsDemo.Post = DS.Model.extend
title: DS.attr 'string'
param: DS.attr 'string'
models/user.coffee
:
EmberAuthRailsDemo.User = DS.Model.extend
email: DS.attr 'string'
param: DS.attr 'string'
We also need to configure the store
for ember-data
. Since we have
namespaced all resource API end points inside /api
, we'll also configure
this in the adapter
.
store.coffee
:
EmberAuthRailsDemo.Store = DS.Store.extend
adapter: DS.ActiveModelAdapter.reopen
namespace: 'api'
We have used the DS.ActiveModelAdapter
, which is an extension of the
default DS.RESTAdapter
. It understands the json structure that we have
defined in our API, which is also the convention from the
active_model_serializers
gem.
ember-auth
comes with the emberData
module, which patches ember-data
's
DS.RESTAdapter
to automatically send along authentication credentials when
a signed in session is present.
Since our API returns the user_id
, we can also ask ember-auth
to auto-load
the user model upon a successful #.
auth.coffee
:
EmberAuthRailsDemo.Auth = Em.Auth.extend
emberData:
userModel: 'user'
ember-auth
will then call store.find('user', auth.get('userId'))
for us,
and set the current user model at auth.user
. We can access it via
auth.get('user')
We can, for example, display the current user's email in our auth/sign-out
template.
templates/auth/sign-out.emblem
:
form submit='signOut'
auth.user.email
button Sign out
We are going to stub out five simple "pages" for testing:
-
/posts
: a list of posts -
/posts/:post_id
: show the requested post -
/users
: (auth-only) a list of users -
/users/:user_id
: (auth-only) show the requested user. -
/sign-in
: an error page for unauthorized access to user pages.
As in ember, each will require a route
, a controller
, and a template
.
Even if not specified, they will be created implicitly. You are encouraged to
read more to
familiarize yourself with the overall structure if you are new to ember.
Routes are standard, but we want the history
API, because hashes in the URL
do not look natural. This can be done by reopen
ing the router
, and setting
the location
config.
router.coffee
:
EmberAuthRailsDemo.Router.reopen
location: 'history'
EmberAuthRailsDemo.Router.map ->
@resource 'posts', ->
@route 'show', { path: '/:post_id' }
@resource 'users', ->
@route 'show', { path: '/:user_id' }
@route 'sign-in'
The post
set of routes are standard, except that we will customize the
post_id
in the posts.show
route, using the param
property we defined
on the post
model.
routes/posts.coffee
:
EmberAuthRailsDemo.PostsIndexRoute = Em.Route.extend
model: ->
@store.findQuery 'post'
EmberAuthRailsDemo.PostsShowRoute = Em.Route.extend
serialize: (model) ->
post_id: model.get 'param'
We want the users
set of routes to be auth-only - non-authenticated users
should be redirected away to the sign-in
page.
We will use the authRedirectable
module for this.
Add the gem and update the bundle.
Gemfile
:
gem 'ember-auth-module-auth_redirectable-rails', '~> 1.0' # auth-only routes
$ bundle update
Include the new module into the ember app.
application.coffee
:
# ...
#= require ember-auth
# ...
#= require ember-auth-module-auth-redirectable
# ...
auth.coffee
:
EmberAuthRailsDemo.Auth = Em.Auth.create
# ...
modules: [
'emberData'
'authRedirectable'
]
authRedirectable:
route: 'sign-in'
Make a sign-in
template to redirect non-authenticated users to.
templates/sign-in.emblem
:
| You need to # first
Routes are same as the posts
set, except that we will mark them as auth-only,
so that the authRedirectable
module will redirect unauthenticated users away.
routes/users.coffee
:
EmberAuthRailsDemo.UsersRoute = Em.Route.extend
authRedirectable: true
EmberAuthRailsDemo.UsersIndexRoute = Em.Route.extend
model: ->
@store.findQuery 'user'
EmberAuthRailsDemo.UsersShowRoute = Em.Route.extend
serialize: (model) ->
user_id: model.get 'param'
We could have added authRedirectable: true
to every route, but since anyone
entering the users.index
route would go through the users
route, declaring
it in the users
route would be enough. Same for the users.show
route.
We don't need custom logic or properties in controllers, so we will let ember generate controllers for us.
We'll stub out the minimum for sanity test: a list for the index
routes,
and either user.email
or post.title
for the show
routes.
templates/posts.emblem
:
outlet
templates/posts/index.emblem
:
ul: each controller
li: linkTo posts.show this
= title
templates/posts/show.emblem
:
h1
= title
linkTo posts.index
| Back to posts list
templates/users.emblem
:
outlet
templates/users/index.emblem
:
ul: each controller
li: linkTo users.show this
email
templates/users/show.emblem
:
h1
email
linkTo users.index
| Back to users list
Finally, let's add some primitive navigation links site-wide.
templates/application.emblem
:
render 'auth'
nav
link-to 'posts.index'
| Posts list
link-to 'users.index'
| Users list
outlet
To complete the expected UI flow, users should be redirected back to where they were after signing in.
Our expectation:
- After a (successful) #, the user should be redirected to
- the previous route
- unless that route is
sign-in
, then redirect to the one beforesign-in
- otherwise (i.e. entry from
sign-in
), redirect tousers
as fallback
- After a (successful) sign out, the user should be redirected to
-
posts
- we use only static redirect here
-
We will use the actionRedirectable
module to achieve this.
Install gem, update bundle, and include the module.
Gemfile
:
gem 'ember-auth-module-action_redirectable-rails', '~> 1.0' # post- #/out redirect
$ bundle update
application.coffee
:
# ...
#= require ember-auth
# ...
#= require ember-auth-module-action-redirectable
# ...
Configure the actionRedirectable
module.
auth.coffee
:
EmberAuthRailsDemo.Auth = Em.Auth.create
# ...
modules: [
'emberData'
'authRedirectable'
'actionRedirectable'
]
# ...
actionRedirectable:
signInRoute: 'users'
signInSmart: true
signInBlacklist: ['sign-in']
signOutRoute: 'posts'
# signOutSmart defaults to false already
# since we are not using smart sign out redirect,
# we don't have to touch signOutBlacklist
That's it! ember-auth
will do all the redirect work for us.
There is an important caveat (bug?) regarding post- sign out behavior. In a
nutshell, ember-data
does not provide any way of clearing the data store,
so the sign out is rather superficial at present. Read more about this issue
in the security notes.
Quick hack-fix? Make the page reload on sign out. This will clear and reload the whole ember app.
controllers/auth/sign-out.coffee
:
EmberAuthRailsDemo.AuthSignOutController = Em.Controller.extend
actions:
signOut: ->
@auth.signOut().then -> window.location.reload true
Continue to Enhancements.