RailsよりモダンなWeb開発が楽そう！CrystalのAmberでTodoアプリAPIを作り、React on Amberでフロントを書いてみる！！

Crystalという言語のフルタックスフレームワークAmberを使ってみようと思いました。
Railsより、モダンなWeb開発に向いてそう！！！

# CrystalのAmberがRailsより、モダンなWeb開発に向いているかもしれない(かもしれない)

これは主にフロントのお話なのですが

- Webpackが**default**で入ってる(RailsのWebpackerのような悪者がいない)
- Babelやcss-loader,file-loaderなどモダンなフロント開発では欠かせないものが**default**で入ってる

# Amberのインストール
###macOS
Crystalも自動でインストールされます。
Homebrew

```
brew tap amberframework/amber
brew install amber
```

MacPorts

```
sudo port selfupdate
sudo port install amber
```

### Ubuntu or Debian

まず、Crystalのインストール

```shell

curl https://dist.crystal-lang.org/apt/setup.sh | sudo bash
sudo apt-get install build-essential crystal
```
次にAmberのインストール

```shell

sudo apt-get install libreadline-dev libsqlite3-dev libpq-dev libmysqlclient-dev libssl-dev libyaml-dev
curl -L https://github.com/amberframework/amber/archive/stable.tar.gz | tar xz
cd amber-stable/
shards install
make install
```
Linuxbrew​でもインストールできる

```shell

brew tap amberframework/amber
brew install amber
```

# Amberでプロジェクトを作る
```shell

amber new amber-todo
cd amber-todo
shards install
```

## AmberでAPIを作る

```shell

amber g api Todo content:string completed:bool
```
**`amber g api`はドキュメントに載っていませんが、0.11.1では使用可能でした**。しかし`plug Amber::Pipe::CORS.new`をコメントアウトする必要があります

```ruby:config/routes.cr
  pipeline :api do
    plug Amber::Pipe::PoweredByAmber.new
    plug Amber::Pipe::Error.new
    plug Amber::Pipe::Logger.new
    plug Amber::Pipe::Session.new
    # plug Amber::Pipe::CORS.new
  end

```
あくまでもドキュメントに乗っていない方法なので使用する際は**注意**してください
postgresを起動しておく

```shell
postgres -D /usr/local/var/postgres
```

必要があれば、database urlを変更

```ruby:config/environments/development.yml
database_url: postgres://postgres:@localhost:5432/amber_todo_development
```

DBを作りマイグレート

```shell
amber db create migrate
```

アクセスできる

```shell
curl http://localhost:3000/todos
[{"id":1,"content":"宿題","completed":false,"created_at":"2018-11-26T09:27:38Z","updated_at":"2018-11-26T09:27:49Z"}]
```



# Reactでフロントをかくぞ！

`node_modules`,`webpack`が標準から導入されてて、おお！！！！すげーさすがやなって感じですww
**React**が慣れてるのでReactで書きます、別にフロントのフレームワークは何でもOKだと思います。

必要なパッケージをインストール、webpack,babelなどはもともと入ってる

```shell
yarn add react react-dom axios 
yarn add -D babel-preset-react
```

jsxでかけるように。

```jsx:config/webpack/common.js
// 省略
      {
        test: /\.js?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['env', 'react']
        }
      }
// 省略

```

## Hello Reactを表示させてみましょう

これらを編集

```jsx:src/assets/javascirpts/App.js
import React, { Component } from 'react'

class App extends Component {
  render() {
    return (
      <div>
        Hello, React!!
      </div>
    )
  }
}

export default App

```
Appを#rootで表示。

```jsx:src/assets/javascirpts/main.js
import Amber from 'amber'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

ReactDOM.render(<App />, document.getElementById('root'))

```

jQuery,Bootstrapはいらないですね
#rootを入れましょう

```html:src/views/layouts/application.slang
doctype html
html
  head
    title Amber Todo using Amber
    meta charset="utf-8"
    meta http-equiv="X-UA-Compatible" content="IE=edge"
    meta name="viewport" content="width=device-width, initial-scale=1"
    link rel="stylesheet" href="/dist/main.bundle.css"
    link rel="apple-touch-icon" href="/favicon.png"
    link rel="icon" href="/favicon.png"
    link rel="icon" type="image/x-icon" href="/favicon.ico"

  body
    #root

    script src="/dist/main.bundle.js"

    - if Amber.settings.auto_reload?
      script src="/js/client_reload.js"

```


## AxiosでAPIにリクエストを送り、画面に表示しよう！

Todosコンポーネントを作りましょう

```jsx:jsx:src/assets/javascirpts/components/Todos.js
import React, { Component } from 'react'
import axios from 'axios'


export default class Todos extends Component {
	constructor(props) {
		super(props)
		this.state = {
			todos: []	
		}
	}
  componentDidMount() {
		axios.get('/todos')
			.then(res => {
				const todos = res.data
				this.setState({ todos })
			})
	}
	render() {
		return (
			<div>
        <ul>
        {
          this.state.todos.map((todo) => (
            <li key={todo.id}>{todo.content}</li>
          ))
        }
        </ul>
      </div>
		)
	}
}

```

Appも変更

```jsx:src/assets/javascirpts/App.js
import React, { Component } from 'react'
import Todos from './components/Todos'

class App extends Component {
  render() {
    return (
      <div>
        <Todos />
      </div>
    )
  }
}

export default App

```

これで一覧は表示できました！
<img width="482" alt="スクリーンショット 2018-12-01 23.33.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/188304/5d545c13-4b77-8290-4823-f2f03ddcab42.png">

### 完了にしたり未完了にしてみる

あとで書く

### まとめ

Crystalはまだリリースされてないものの、意外と使えました。
これからRailsの代わりになっていくかもしれない。