Guide to Rails and Preact (Part 2)

มาต่อจากตอนที่แล้ว part 1 เราได้สร้างโปรเจค book_store เอาไว้ แต่ยังไม่ได้มีการสร้างฟอร์มสำหรับเก็บข้อมูลหนังสือกันเลย สำหรับในบทความนี้จะลองเป็นการพัฒนาโปรแกรมในรูปแบบลูกผสม โดยจะให้ Rails ทำหน้าที่ในการจัด routing และ render หน้าเว็บหลัก แต่จะมีบางส่วนที่จะพัฒนาเป็น Component ขึ้นและใช้เป็น CSR สร้าง Component สำหรับการบันทึกข้อมูลหนังสือ

$ rails generate model Book name:string author:string 'price:decimal{10,2}'
$ rails generate scaffold_controller Book

config/routing.rb

  resources :books

app/javascripts/books/bookForm.jsx

import { h, render, Component } from 'preact'
import { getCsrfToken } from 'helpers/form'

class BookForm extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: '',
      author: '',
      price: 0
    }
    this.onChange = this.onChange.bind(this)
    this.onSubmit = this.onSubmit.bind(this)
  }

  onChange = (event) => {
    console.log(event)
    this.setState({ [event.target.name]: event.target.value })
  }

  onSubmit = (event) => {
    event.preventDefault();
    fetch('/books', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': getCsrfToken()
      },
      body: JSON.stringify(this.state)
    })
    .then(response => response.json())
    .then(data => {
      if (data.errors) {
        // handle errors
      } else {
        window.location.replace(data.next_path)
      }
    })
  }

  render() {
    return (
      <div>
        <h2>สร้างหนังสือใหม่</h2>
        <form class="control" onSubmit={this.onSubmit}>
          <div class='field'>
            <label>ชื่อหนังสือ</label>
            <input type="text" name="name" value={this.state.name} onChange={this.onChange}></input>
          </div>
          <div class='field'>
            <label>ผู้เขียน</label>
            <input type="text" name="author" value={this.state.author} onChange={this.onChange}></input>
          </div>
          <div class='field'>
            <label>ราคา</label>
            <input type="number" name="price" pattern="(\d{3})([\.])(\d{2})" value={this.state.price} onChange={this.onChange}></input>
          </div>
          <button type="submit">สร้าง</button>
          <button onClick={() => window.history.go(-1)}>กลับ</button>
        </form>
      </div>
    )
  }
}

export default BookForm

app/javascripts/packs/book.js

import { h, render } from 'preact'
import BookForm from '../books/bookForm'

let checkReady = () => {
  return new Promise((resolve) => {
    if (document.readyState !== 'loading') {
      return resolve()
    }
    document.addEventListener('DOMContentLoaded', () => resolve())
  })
}

checkReady().then(() => {
  let form = document.querySelector('.book-form')
  render(<BookForm />, form)
})

app/views/books/new.html.erb

<%= javascript_packs_with_chunks_tag 'book' %>

<div class="book-form"></div>

preact BookForm Component

💡อะไรที่เราได้จากการพัฒนาโปรแกรมในรูปแบบนี้