Skip to content

code related to a 3/22/19 talk at Prime Digital Academy

Notifications You must be signed in to change notification settings

jamemackson/lux-ember-crud

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 

Repository files navigation

node (lux) + ember -- crud basics

a full stack crud example

Lux ember crud basics

a full stack crud example

core technologies used

  • ember.js // frontend SPA
  • node using lux-framework // api
  • postgres // database
  • sqlite // database for tests

pre-req's

  • brew >> nvm >> node (yarn optional)
    npm i -g yarn ember lux-framework

create lux api

run their cli to scaffold a new project lux new lux-api

cd into the new project cd lux-api

install database adapters we'll need (sqlite only used for testing) yarn add sqlite3 pg or npm install sqlite3 pg --save

install dependancies
yarn or npm install

commit: default project structure

generate resources
lux g resource post author:belongs-to title:string slug:string body:text
lux g resource author posts:has-many name:string

  • go in and fix author's has many posts inverse name in model

commit: new resources generated

setup some configs

setup postgres connection in api/config/database.js

// get connection props from env
const {
  DB_HOST = 'localhost',
  DB_PORT = '5432',
  DB_USER = 'postgres',
  DB_PASS = '',
  DB_NAME = 'api_dev'
} = process.env;

  // wire up connection properties
  development: {
    driver: 'pg',
    database: DB_NAME,
    host: DB_HOST,
    port: DB_PORT,
    username: DB_USER,
    password: DB_PASS
  },

setup CORS

export default {
  server: {
    cors: {
      origin: '*',
      enabled: true,

      headers: [
        'Accept',
        'Content-Type',
        'Authorization'
      ],

      methods: [
        'GET',
        'POST',
        'PATCH',
        'DELETE',
        'HEAD',
        'OPTIONS'
      ]
    }
  },

  logging: {
    level: 'DEBUG',
    format: 'text',
    enabled: true,
    filter: {
      params: []
    }
  }
};

commit: database and CORS config

generate database tables

lux db:migrate

give us some data to start off with

INSERT INTO "public"."authors"("id", "name", "created_at", "updated_at")
VALUES (1, 'timmy', '2019-03-21 22:26:31-05', NULL);

INSERT INTO "public"."authors"("id", "name", "created_at", "updated_at")
VALUES (2, 'suzie', '2019-03-21 22:26:37-05', NULL);

INSERT INTO "public"."posts"("id", "author_id", "title", "slug", "body", "created_at", "updated_at")
VALUES (2, 1, 'hipster ipsum', 'hipster-ipsum', 'Lorem ipsum dolor amet pug hoodie gluten-free iceland, iPhone disrupt sriracha synth raw denim messenger bag vape. Mlkshk 90''s kale chips vaporware, pug post-ironic selfies live-edge biodiesel art party kombucha. Butcher freegan vaporware, bushwick put a bird on it austin single-origin coffee yr pitchfork lomo. Cold-pressed franzen cornhole flannel cardigan offal, shoreditch sustainable everyday carry. Bitters asymmetrical glossier cardigan try-hard.
', '2019-03-20 23:52:24-05', '2019-03-20 23:52:26-05');
INSERT INTO "public"."posts"("id", "author_id", "title", "slug", "body", "created_at", "updated_at")
VALUES (1, 1, 'pirate ipsum', 'pirate-ipsum', 'Splice the main brace loaded to the gunwalls crack Jennys tea cup landlubber or just lubber ho lass pirate Jack Tar poop deck Shiver me timbers. Quarterdeck bilge rat to go on account league barkadeer gunwalls crimp gabion driver wench. Reef trysail lateen sail main sheet loot bilge barque American Main squiffy bounty.<br>
', '2019-03-20 23:34:29-05', '2019-03-20 23:34:37-05');
INSERT INTO "public"."posts"("id", "author_id", "title", "slug", "body", "created_at", "updated_at")
VALUES (3, 2, 'things', 'things', 'Lorem ipsum dolor amet pug hoodie gluten-free iceland, iPhone disrupt sriracha synth raw denim messenger bag vape. Mlkshk 90''s kale chips vaporware, pug post-ironic selfies live-edge biodiesel art party kombucha. Butcher freegan vaporware, bushwick put a bird on it austin single-origin coffee yr pitchfork lomo. Cold-pressed franzen cornhole flannel cardigan offal, shoreditch sustainable everyday carry. Bitters asymmetrical glossier cardigan try-hard.
', '2019-03-21 23:00:10-05', NULL);
INSERT INTO "public"."posts"("id", "author_id", "title", "slug", "body", "created_at", "updated_at")
VALUES (4, 2, 'other things', 'other-things', 'Splice the main brace loaded to the gunwalls crack Jennys tea cup landlubber or just lubber ho lass pirate Jack Tar poop deck Shiver me timbers. Quarterdeck bilge rat to go on account league barkadeer gunwalls crimp gabion driver wench. Reef trysail lateen sail main sheet loot bilge barque American Main squiffy bounty.<br>
', NULL, NULL);

create ember app

scaffold a new ember app
ember new ember-frontend --yarn

cd into the new project folder
cd ember-frontend
// remove .git folder (presentation only)
rm -rf .git/

commit: ember app generated by ember 3.7.1

generate out matching models to what we created in api
ember g model post author:belongsTo title:string slug:string body:string
ember g model author posts:hasMany name:string

commit: created post and author models

start dev server yarn start (calls ember serve)

open browser to show default ember app

open code to see what we’ve created so far…

note general folder structures
lux-api: app/controllers app/models/ app/serializers
ember-frontend: app/models app/routes app/components app/templates

update site layout

./ember-frontend/app/templates/application.hbs

<h1>Hello Ember + Node (lux)</h1>
<hr>
{{outlet}}

commit: added header to application template

create adapter and wire up connection to api

ember g adapter application

update to set the hostname of our api

  host: `http://localhost:4000`

commit: created application adapter with api hostname

show posts on application.index route

ember g route index

update model hook

  model() {
    return this.get('store').findAll('post');
  }

show posts in the template

<pre>index route</pre><br> 
{{#each model as |post|}}
  <h1>{{post.title}}</h1>
  <p>by <em>{{post.author.name}}</em></p>
  <div class="post-body">
    {{{post.body}}}
  </div>
{{/each}}

commit: added index route

convert post display into component

ember g component blog-post

move hbs content for post into component template

  <h1>{{post.title}}</h1>
  <p>by <em>{{post.author.name}}</em></p>
  <div class="post-body">
    {{{post.body}}}
  </div>

// index.hbs

{{#each model as |post|}}
  {{blog-post post=post}}
{{/each}}

add ability to edit the post

add isEditing flag in component js isEditing: false,

add event handlers to component js

  actions: {
    toggleEditing() {
      this.set('isEditing', !this.get('isEditing'));
    },
    saveEdits(post) {
      post.save();
      this.set('isEditing', false);
    },
    cancelEdits(post) {
      post.rollbackAttributes();
      this.set('isEditing', false);
    }
  }
  • add hbs conditional on isEditing
<h1>{{post.title}}</h1>
<p>by <em>{{post.author.name}}</em></p>
{{#if isEditing}}
  <button {{action "cancelEdits" post}}>cancel</button>
  <button {{action "saveEdits" post}}>save</button>
  <br>
  Edit Title: {{input value=post.title}}<br>
  Body:<br>
  {{textarea value=post.body cols="100" rows="15"}}
{{else}}
  <button {{action "toggleEditing"}}>EDIT</button>
  <p>by <em>{{post.author.name}}</em></p>
  <div class="post-body">
    {{yield}}
    {{{post.body}}}
  </div>
{{/if}}

commit: add ability to edit post

About

code related to a 3/22/19 talk at Prime Digital Academy

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published