NAV Navbar
Logo
code

Introduction

React Over Crystal, Kemal, & Yarn

Current version is 0.1.0

Welcome to the ROCKY Stack

I built this as an experiment to put together the best libraries to build a modern yet simple stack.

I chose to base my stack

Installation

Follow the code on the right for the installation commands that you will have to run on your operating systems terminal / console.

Requirements

Rocky Project

git clone https://github.com/codingphasedotcom/rocky

Download or clone the ROCKY Project

https://github.com/codingphasedotcom/rocky

homebrew for mac

OS X (Mac)

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Homebrew

brew update
brew install crystal-lang
brew install yarn

Make sure you have homebrew

Ubuntu / Linux

curl https://dist.crystal-lang.org/apt/setup.sh | sudo bash
sudo apt-get install crystal
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

Debian / Ubuntu

For other OSes and distros check the official documentation.

https://yarnpkg.com/en/docs/install#linux-tab

Dependencies

Get Crystal Dependencies

#terminal
shards install

Get all the “Backend” crystal dependencies

Get Yarn Dependencies

#terminal
yarn install

Get all the “Frontend” dependencies

Get Gulp

npm install --global gulp-cli

Install Gulp to be

Getting Started

#terminal
yarn run server

To test everything is good run the server.

Now if you visit http://localhost:3000/ you should see the welcome home page

Folders Structure

#Folders
|-- .bowerrc
    |-- .jshintrc
    |-- .jshintrc2
    |-- Gruntfile.js
    |-- README.md
    |-- bower.json
    |-- karma.conf.js
    |-- package.json
    |-- app
        |-- app.js
        |-- db.js
        |-- directoryList.md
        |-- index.html
        |-- mddir.js
        |-- routing.js
        |-- server.js
        |-- _api
            |-- api.groups.js
            |-- api.posts.js
            |-- api.users.js
            |-- api.widgets.js
        |-- _components
            |-- directives
                |-- directives.module.js
                |-- vendor
                    |-- directive.draganddrop.js
            |-- helpers
                |-- helpers.module.js
                |-- proprietary
                    |-- factory.actionDispatcher.js
            |-- services
                |-- services.cardTemplates.js
                |-- services.cards.js
                |-- services.groups.js
                |-- services.posts.js
                |-- services.users.js
                |-- services.widgets.js
        |-- _mocks
            |-- mocks.groups.js
            |-- mocks.posts.js
            |-- mocks.users.js
            |-- mocks.widgets.js

This is an example not final

HTTP

Routing

Simpler Route

#src/routes/web.cr

get "/" do
  "Hello World!"
end

All Routes are declared on the file src/routes/web.cr

when you visit http://localhost/ you will see the page return “Hello World!”

This endpoint retrieves all kittens.

REST Calls

#src/routes/web.cr

get "/" do
.. show something ..
end

post "/" do
.. create something ..
end

put "/" do
.. replace something ..
end

patch "/" do
.. modify something ..
end

delete "/" do
.. annihilate something ..
end

You can handle HTTP methods as easy as writing method names and the route with a code block. Kemal will handle all the hard work.

Static Files

#Files

app/
  src/
    your_app.cr
  public/
    js/
      jquery.js
      your_app.js
    css/
      your_app.css
    index.html

Open index.html and add

#src/public/test.html

<html>
 <head>
   <script src="/js/jquery.js"></script>
   <script src="/js/your_app.js"></script>
   <link rel="stylesheet" href="/css/your_app.css"/>
 </head>
 <body>
   ...
 </body>
</html>

Add your files to public directory and Kemal will serve these files immediately.

Static File Options

#src/rocky.cr

serve_static false

Disabling Static Files

By default Kemal serves static files from public folder. If you don’t need static file serving at all(if you are only running an API) you can disable it

Error Handling

Error handlers run within the same context as routes and before filters which means you get all the power of those.

404 Not Found

error 404 do
  "This is a customized 404 page."
end

When a Kemal::Exceptions::NotFound exception is raised, or the response’s status code is 404, the error 404 handler is invoked:

You can customize the built-in error 404 handler.

Custom error handlers for status codes

Just like error 404 handler you can install custom error handlers for different status codes.

error 403 do “Access Forbidden!” end

get “/” do |env| env.response.status_code = 403 end

Views

Render a View

Views are server side rendered pages

#src/routes/web.cr

get "/account" do
  render "src/views/hello.ecr"
end
Macro Value1 Detail
render src/views/hello.ecr you pass down the ecr view that you want to render on that route

Pass Variables to View

On The Route

#src/routes/web.cr

get "/user" do |env|
  name = "Joe"
  render "src/views/hello.ecr"
end

You declare the route route and inside the block you declare the variable.

On The View

#src/views/hello.ecr

<div>
  <%= name %>
<div>

Now inside the ecr file which is the view you want to render. You want to do an embedded tag with the name of the variable so it can show on your page.

Layouts

Layouts are a great way to keep your code DRY (Dont Repeat Yourself) For example lets say all your pages have the same header and footer throughout all the pages and all that changes is the content area do you go and copy the header and footer to every page No… we just make one main layout and then set content tag where you will show your view.

On The Route

On The Route

#src/views/pages/user.ecr

get "/user" do
  name = "joe"
  render "src/views/pages/user.ecr", "src/views/layouts/main.ecr"
end
Macro Value1 value2 Detail
render src/views/hello.ecr src/views/layouts/main.ecr you pass down the ecr view that you want to render on that route and layout page
view location layout location

On The View

On The View

#src/views/hello.ecr

<div class="content-area">
  Hey, here goes my html
</div>

Just put the code you want to show up for that view

On The Layout

On The Layout

#src/views/layouts/main.ecr

<html>
<head>
  <title>My Kemal Application</title>
</head>
<body>
  <header>
    <ul class="menu">
      <li><a href="#">Home</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </header>
  <%= content %>
</body>
</html>

Use <%= content %> tag to display the page content on the layout

content_for & yield_content

content_for is a great for situations where you might want to change something from the layout on every view. For example a page title or a css script.

On The View

On The View

#src/views/pages/hello.ecr

<% content_for "title" do %>
<title>My Kemal Application</title>
<% end %>

<% content_for "css" do %>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<% end %>

<div class="content-area">
  this will be the view content
</div>

<% content_for "javascript" do %>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<% end %>

Use the content_for and give it a name. You can have multiple content_for macros on a view. For example one for the title, another for css, and another for javascript.

On The Layout

On The Layout

#src/views/layouts/main.ecr

<html>
<head>
  <%= yield_content "title" %>
  <%= yield_content "css" %>
</head>
<body>
  <header>
    <ul class="menu">
      <li><a href="#">Home</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
  </header>
  <%= content %>
  <%= yield_content "javascript" %>
</body>
</html>

add the yield_content with the name of the content you want to display.

First View

#src/views/includes/navigation.ecr

<ul class="menu">
  <li><a href="#">Home</a></li>
  <li><a href="#">Contact</a></li>
</ul>

You can include any view in another view

#src/views/layouts/main.ecr

<html>
  <head>
    <%= yield_content "title" %>
    <%= yield_content "css" %>
  </head>
  <body>
    <header>
      <ul class="menu">
        <li><a href="#">Home</a></li>
        <li><a href="#">Contact</a></li>
      </ul>
    </header>
    <%= render "src/views/includes/navigation.ecr" %>
    <%= content %>
    <%= yield_content "javascript" %>
  </body>
</html>

Database

Views

React Over Crystal and Kemal

Welcome to the ROCKY Stack

require 'kittn'

api = Kittn::APIClient.authorize!('meowmeowmeow')
api.kittens.get
import kittn

api = kittn.authorize('meowmeowmeow')
api.kittens.get()
curl "http://example.com/api/kittens"
  -H "Authorization: meowmeowmeow"
const kittn = require('kittn');

let api = kittn.authorize('meowmeowmeow');
let kittens = api.kittens.get();

The above command returns JSON structured like this:

[
  {
    "id": 1,
    "name": "Fluffums",
    "breed": "calico",
    "fluffiness": 6,
    "cuteness": 7
  },
  {
    "id": 2,
    "name": "Max",
    "breed": "unknown",
    "fluffiness": 5,
    "cuteness": 10
  }
]

This endpoint retrieves all kittens.

ORM

This endpoint retrieves all kittens.

Security

Views

React Over Crystal and Kemal

Welcome to the ROCKY Stack

require 'kittn'

api = Kittn::APIClient.authorize!('meowmeowmeow')
api.kittens.get
import kittn

api = kittn.authorize('meowmeowmeow')
api.kittens.get()
curl "http://example.com/api/kittens"
  -H "Authorization: meowmeowmeow"
const kittn = require('kittn');

let api = kittn.authorize('meowmeowmeow');
let kittens = api.kittens.get();

The above command returns JSON structured like this:

[
  {
    "id": 1,
    "name": "Fluffums",
    "breed": "calico",
    "fluffiness": 6,
    "cuteness": 7
  },
  {
    "id": 2,
    "name": "Max",
    "breed": "unknown",
    "fluffiness": 5,
    "cuteness": 10
  }
]

This endpoint retrieves all kittens.