Skip to content

Instantly share code, notes, and snippets.

@AndyDangerous
Created November 3, 2014 19:33
Show Gist options
  • Save AndyDangerous/7f57cc85471330c54852 to your computer and use it in GitHub Desktop.
Save AndyDangerous/7f57cc85471330c54852 to your computer and use it in GitHub Desktop.
<iframe width="420" height="315" src="//www.youtube.com/embed/LYN8BXmb6h4" frameborder="0" allowfullscreen></iframe>
There are some tutorials out there to help you get started with pairing the excellent Ember front end javascript framework with a Rails back end API. It can be a little harder to find a condensed source to help you go beyond simple GET requests.
This tutorial is based off of a project called [Snowcial](www.snowcial.pw), and will cover implementing CRUD actions for an existing `groups` model. You can substitute this with whatever model makes sense for your project. Requirements include a working app* with `index` and `show` actions. We will go over adding `create`, `update`, and `destroy`. I'll also assume that you are comfortable with Ruby and Rails already though you'll only need passing understanding of javascript and Ember.
*App, in this case, means a Rails app providing a JSON API and an Ember front end consuming it. [This set of tutorials](http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html) from [Dockyard](http://dockyard.com/) will get you up to speed.
###### A note about testing
Testing should be first and foremost on your mind when thinking about implementing new functionality for your apps. Unfortunately it is outside the scope of this tutorial. Test your apps. Ask for help or advice if you need it.
#### Ember
##### Step 1: Routes
Routes in Ember are not the same as routes in Rails, but they are also not entirely different. We'll start here. create a new `app/routes/groups/create.js` file and add the following. We are adding a create function for the `group` model and the action to go along with it.
```javascript
//app/routes/groups/create.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('group', {
name: ''
});
},
actions: {
create: function() {
var my_model = this.controller.get('model');
my_model.save();
this.transitionTo('groups.show', my_model);
}
}
});
```
Follow suit for the `edit`, `index`, and `show`.
```javascript
//app/routes/groups/edit.js
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
submit: function() {
var my_model = this.controller.get('model');
my_model.save();
this.transitionTo('groups.show', my_model);
}
}
});
```
```javascript
//app/routes/groups/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('group');
}
});
```
```javascript
//app/routes/groups/show.js
import Ember from 'ember';
export default Ember.Route.extend({
actions:{
delete: function() {
this.controller.get('model').destroyRecord();
this.transitionTo('groups.index');
}
}
});
```
##### Step 2: Templates
You will need your templates to have forms for your `create` and `edit` actions. Ember's magic will help you out. Unfortunately, my editor doesn't have handlebars highlighting. That's a thing that you'll want unless you're a total masochist or Swiss, in which case you will prefer [Emblem](http://emblemjs.com/).
```javascript
//app/templates/groups/create.hbs
<h4 class="create-new-group">Create New Group</h4>
<p>Name:&nbsp;{{input value=name class='group-name'}}</p>
<p>Description:&nbsp;{{input value=description class='group-description'}}</p>
<p><button type='submit' {{action 'create'}} class='commit-group-creation'>Submit</button></p>
```
```javascript
//app/templates/groups/edit.hbs
<h4>Edit</h4>
<p>Name:&nbsp;{{input value=name class='group-name'}}</p>
<p>Description:&nbsp;{{input value=description class='group-description'}}</p>
<p><button type='submit' {{action 'submit'}} class='commit-group-change'>Submit</button></p>
```
```javascript
//app/templates/groups/index.hbs
<h3>Groups</h3>
<table>
<thead>
<th>Name</th><th>Trips Taken</th>
</thead>
<tbody>
<p>{{#link-to 'groups.create' class="create-group"}}Create{{/link-to}}</p>
{{#each}}
<tr>
<td>
{{~#link-to 'groups.show' this}}
{{name}}{{~/link-to}}</td><td>{{trips.length}}</td>
</tr>
{{/each}}
</tbody>
</table>
```
```javascript
//app/templates/groups/show.hbs
<h4>{{name}}</h4>&nbsp;
{{link-to 'Edit' 'groups.edit' model class='edit-group'}}
<button {{action 'delete'}} class="delete-group">Delete</button>
<h5>Group Description:</h5>
<p>{{description}}</p>
<h5>Trips</h5>
<ul>
{{#each trips}}
<li>{{name}}</li>
{{/each}}
</ul>
```
At this point, you may feel the urge to delete `app/templates/groups.hbs`. Go for it. Or don't. It's basically just another partial that can hold your various `groups` templates.
##### Step 3: `router.js`
Lastly, you'll need to add these new routes to your `router.js`
```javascript
//app/router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('demo');
this.resource('groups', function() {
this.route('show', {path: ':group_id'});
this.route('edit', {path: ':group_id/edit'});
this.route('create', {path: 'create'});
});
});
export default Router;
```
#### Rails
##### Step 1: Serializers
If you don't already have a serializer for your model then you'll need to add `gem 'active_model_serializers'` to your `Gemfile` and generate a new serializer.
```terminal
$ rails generate serializer group
```
The most important part of your serializer is adding the correct attributes. I have added a bit more to mine because I want some of the associations to come along as part of the JSON.
```ruby
#app/serializers/group_serializer.rb
class GroupSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :id, :name, :description
has_many :trips
end
```
*Note that `embed` is deprecated.
##### Step 2: CSRF Considerations
Rails has a default protection against [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)) attacks. While an in-depth analysis of site security is beyond the scope of this tutorial, you can avoid the problem by changing your ApplicationController.
```ruby
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
end
```
That should get you up and running. If you have questions or comments then sound off below or feel free to reach out on [twitter](http://twitter.com/amention) or [GitHub](http://github.com/AndyDangerous).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment