HotwireとCount Trewindによるレール7.0デモ


2022年までに新しいレールが発売された.このリリースでは、レールが大幅に別のフレームワークから大幅に最も困難な問題を取り除くことによって目立つようになりますreplacing NodeJS with Hotwire as a default UI/UX . しかし、まだ追加のアプローチのインポートマップをnodejsにアクセスできます.
この記事では、より詳細にRails
このデモでは、次のような重要なコンポーネントを使用するオリジナルのものをフォークしました

  • Hotwire  - UI/UXおよびJavaScriptフレームワークとして(デフォルト)

  • Tailwind CSS  - CSSフレームワーク

  • ActionText - テキストボックスのリッチテキストコンテンツ

  • 前もって
    推奨バージョン
    rvm: 1.29.12
    ruby: 3.0.3
    rails: 7.0.0
    

    1 )初期アプリケーションプロジェクト
  • 新しいブログを作成します
  • rails new blog --css tailwind
    
  • ブログ投稿の足場を生成する
  • rails g scaffold post title
    
  • ActionTextをインストールする
  • rails action_text:install
    
  • Rails DBを移行する
  • rails db:create db:migrate
    

    リッチテキスト領域を追加する
    コンテンツの追加:ActionTextからモデル、ビュー、およびコントローラへのリッチテキスト領域として
    すべてのHTML.ERBファイルは、Tailwind CSSで使われるクラスを含んでいました
  • モデルポスト
  • # app/models/post.rb
    class Post < ApplicationRecord
      validates :title, presence: true
    
      has_rich_text :content
    end
    
  • プロフィール-投稿テンプレート
  • <!-- app/views/posts/_form.html.erb -->
    <!-- ... -->
    <!-- add field :content -->
    <div class="my-5">
      <%= form.label :content %>
      <%= form.rich_text_area :content, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
    </div>
    <!-- ... -->
    
    <!-- app/views/posts/_post.html.erb -->
    <!-- ... -->
    <!-- add field :content -->
     <p class="my-5">
       <%= @post.content %>
     </p>
    <!-- ... -->
    
    <!-- app/views/posts/show.html.erb -->
    <!-- ... -->
    <!-- add field :content -->
     <p class="my-5 inline-block">
       <%= @post.content %>
     </p>
    <!-- ... -->
    
  • コントローラ-ポスト
  • # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
    # ...
     private
       def post_params
         params.require(:post).permit(:title, :content) # add content
       end
    end
    

    3 )ポストフレームにターボフレームを適用する
    新しい投稿をクリックすると、新しい投稿ページがインデックスページに表示されます
  • プロフィール-投稿インデックスページ
  • <!-- app/views/posts/index.html.erb -->
    <div class="w-full">
      <div class="flex justify-between items-center">
        <h1 class="text-white text-lg font-bold text-4xl">Posts</h1>
        <%= link_to 'New Post', new_post_path,
          class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium",
          data: { 'turbo-frame': 'new_post' }
        %>
      </div>
    
      <%= turbo_frame_tag :new_post %>
    
      <div class="min-w-full">
        <%= turbo_frame_tag :posts do %>
          <%= render @posts %>
        <% end %>
      </div>
    </div>
    
  • プロフィール-ポスト新しいページ
  • <!-- app/views/posts/new.html.erb -->
    <%= turbo_frame_tag :new_post do %>
      <div class="w-full bg-white p-4 rounded-md mt-4">
        <h1 class="text-lg font-bold text-4xl">New post</h1>
    
        <%= render "form", post: @post %>
    
        <%= link_to 'Back to posts', posts_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
      </div>
    <% end %>
    

    4 )ビューにターボストリームを適用する
  • コントローラにCRUDを加える
  • # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
      # ...
      def create
        @post = Post.new(post_params)
    
        respond_to do |format|
          if @post.save
            format.turbo_stream # add format turbo_stream
            format.html { redirect_to posts_path }
            format.json { render :show, status: :created, location: @post }
          else
            format.turbo_stream # add format turbo_stream
            format.html { render posts_path, status: :unprocessable_entity }
            format.json { render json: @post.errors, status: :unprocessable_entity }
          end
        end
      end
    
      def update
        respond_to do |format|
          if @post.update(post_params)
            format.turbo_stream # add format turbo_stream
            format.html { redirect_to posts_path, notice: "Post was successfully updated." }
            format.json { render :show, status: :ok, location: @post }
          else
            format.turbo_stream # add format turbo_stream
            format.html { render posts_path, status: :unprocessable_entity }
            format.json { render json: @post.errors, status: :unprocessable_entity }
          end
        end
      end
    
      def destroy
        @post.destroy
        respond_to do |format|
          format.turbo_stream # add format turbo_stream
          format.html { redirect_to posts_url, notice: "Post was successfully destroyed." }
          format.json { head :no_content }
        end
      end
      # ...
    end
    
  • テンプレートファイルを作成する
  • アプリケーション/ビュー/投稿/作成.ターボ流ERB
  • アプリ/ビュー/ポスト/更新.ターボ流ERB
  • アプリケーション/ビュー/ポスト/破壊.ターボ流ERB
  • <!-- app/views/posts/create.turbo_stream.erb -->
    <% if @post.errors.present? %>
       <%= notice_stream(message: :error, status: 'red') %>
       <%= form_post_stream(post: @post) %>
    <% else %>
       <%= notice_stream(message: :create, status: 'green') %>
    
       <%= turbo_stream.replace :new_post do %>
          <%= turbo_frame_tag :new_post %>
       <% end %>
    
       <%= turbo_stream.prepend 'posts', partial: 'post', locals: { post: @post } %>
    <% end %>
    
    <!-- app/views/posts/update.turbo_stream.erb -->
    <% if @post.errors.present? %>
      <%= notice_stream(message: :error, status: 'red') %>
    
      <%= form_post_stream(post: @post) %>
    
    <% else %>
      <%= notice_stream(message: :update, status: 'green') %>
    
      <%= turbo_stream.replace dom_id(@post), partial: 'post', locals: { post: @post } %>
    <% end %>
    
    <!-- app/views/posts/destroy.turbo_stream.erb -->
    <%= notice_stream(message: :delete, status: 'green') %>
    <%= turbo_stream.remove @post %>
    

    5 )通知を実装する
    ヘルパーとして通知を実装し、ルーティングを許可し、コントローラを呼び出してビューに表示します
    これらのステップは、JavaScript
  • ヘルパーを作成する
  • # app/helpers/posts_helper.rb
    module PostsHelper
      NOTICE = {
        create: 'Post created successfully',
        update: 'Post updated successfully',
        delete: 'Post deleted successfully',
        error: 'Something went wrong'
      }.freeze
    
      def notice_stream(message:, status:)
        turbo_stream.replace 'notice', partial: 'notice', locals: { notice: NOTICE[message], status: status }
      end
    
      def form_post_stream(post:)
        turbo_stream.replace 'form', partial: 'form', locals: { post: post }
      end
    end
    
  • メインフレームファイルにターボフレームを追加する
  • <!-- app/views/layouts/application.html.erb -->
     <%= turbo_frame_tag :notice, class: 'w-full' do %>
     <% end %>
    
  • ポストの作成通知テンプレート
  • <!-- app/views/posts/_notice.html.erb -->
    <p class="animate-pulse opacity-80 w-full py-2 px-3 bg-<%= status %>-50 mb-5 text-<%= status %>-500 font-medium rounded-lg inline-block" id="notice"><%= notice %></p>
    

    6 )通知の実装-クリア通知
  • 通知ルートをクリア
  • <!-- app/views/posts/_form.html.erb --->
    # config/routes.rb
    get '/notice', to: 'posts#clear_message'
    
  • 投稿でクリア通知を追加する
  • <!-- app/views/posts/_form.html.erb -->
      <%= turbo_frame_tag dom_id post do %>
        <%= form_with(
          model: post, 
          id: 'form',
          class: "contents",
          html: {
            data: { controller: 'notice', action: 'submit->notice#clear' }
          }
        ) do |form| %>
    
       <!-- fields  --->
    
       <% end %>
    <% end %>
    
  • コンフィグ間隔(5000 ms)の後、明確な通知をトリガーしてください
  • # app/javascript/controllers/notice_controller.js
    import { Controller } from "@hotwired/stimulus"
    import { FetchRequest } from "@rails/request"
    
    // Connects to data-controller="notice"
    export default class extends Controller {
      clear(event) {
        event.preventDefault()
    
        setTimeout(async () => {
          const request = new FetchRequest("get", '/notice', { responseKind: "turbo-stream" })
          await request.perform()
        }, 5000)
    
        event.target.requestSubmit()
      }
    }
    
  • コントローラのポストにアクションを追加する
  • # app/controllers/posts_controller.rb
    class PostsController < ApplicationController
     # ... actions
    
     def clear_message
      respond_to do |format|
        format.turbo_stream
      end
     end
    end
    

    7 )設定ランディングページ
  • ページをインデックスページにリダイレクトする
  • # config/routes.rb
    Rails.application.routes.draw do
      # Set Post index to landing page
      root 'posts#index'
    end
    
  • 検証のためのRailsサーバの起動
  • rails s
    
  • このアプリの特徴
  • 単一のページにすべてのポストを表示する
  • 各ポストにコメントを表示する拡大
  • クラッドポスト
  • ポストの下でCRUDコメント
  • 成功または失敗したときに、通知、作成、削除の通知

  • 資源
  • 終了コードベースdemo-blog-hotwire:initial_completed


  • 続きを読む
  • More Rails 7 Feature in detail

  • Hotwire with previous Rails
  • Rails 7 and Javascript
  • Official Rails 7 release note

  • リソース属性
    Blender
    Number art