LoginSignup
2
2

More than 5 years have passed since last update.

MyFirstRails #6 Stimulusでリアルタイムプレビュー機能!

Last updated at Posted at 2019-02-07

Stimulus サンプル

概要

Railsにこれから初めて触れる方を対象にしたチュートリアルです
RailsとStimulusを使ってリアルタイムプレビュー機能を実装してみます!

実際に作ったものはこちら

stimulus.gif

チュートリアル

Railsのひな型を作る

まず、rails newを実行し、Railsアプリのひな型を作成します。

rails new stimulus --webpack=stimulus

--webpackはRailsでWeboackを使いやすくしたWebpackerというものを使用するというオプションです

Vue、React、Angular、Elm、Stimulusを使用することができます

今回はStimulusを使用するので--webpack=stimulusとしています

次に、作成したRailsアプリのディレクトリへと移動します。

cd stimulus

Foremanを使う

Webpackerを使う場合、ruby ./bin/webpack-dev-serverというコマンドを実行しつつ、rails sでローカルサーバーを起動する必要があります

その為、現状のままではターミナルを複数開いておく必要があり、少々面倒です

そこで、複数のコマンドを並列して実行できるforemanを使用します

まず、Gemfilegem 'foreman'を追記します

Gemfile
gem 'foreman'

その後、bundle install

bundle install

次に、foremanで使用するProcfile.devを作成します

Procfile.dev
web: bundle exec rails s
webpacker: ruby ./bin/webpack-dev-server

あとは、foreman start -f Procfile.devをターミナルで実行するだけです

foreman start -f Procfile.dev

localhost:5000にアクセスできればOkです(foremanを使用する場合、使用するポートが5000へと変更されています)

Stimulusでリアルタイムプレビューを実装

まず、app/javascript/controllers/post_controller.jsを作成します

app/javascript/controllers/post_controller.js
import { Controller } from "stimulus"

export default class extends Controller {
    static targets = ["title", "content", "preview"]

    content() {
        this.previewTarget.innerHTML = this.contentTarget.value
    }
}

次に、app/views/posts/_form.html.erbを以下のように編集します

<div  data-controller="post">
  <div class="form-left">
    <%= form_with(model: post, local: true) do |form| %>
      <% if post.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

          <ul>
            <% post.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </ul>
        </div>
      <% end %>

      <div class="field">
        <%= form.label :title %>
        <%= form.text_field :title %>
      </div>

      <div class="field">
        <%= form.label :content %>
        <%= form.text_field :content, 'data-target': 'post.content', 'data-action': 'input->post#content' %>
      </div>

      <div class="actions">
        <%= form.submit %>
      </div>
    <% end %>
  </div>

  <div class="form-right">
    <h1>Content</h1>
    <div data-target="post.preview"></div>
  </div>
</div>

<%= javascript_pack_tag 'application.js' %>

最後に、app/assets/stylesheets/posts.cssを以下のように修正します

app/assets/stylesheets/posts.css
// Place all the styles related to the posts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

.form-left{
    width: 50%;
    float: left;
}

.form-right{
    width: 50%;
    float: right;
}

これでリアルタイムプレビュー機能が実装できました!

Trixでリッチなテキストエディターを使う

trixGemfileに追加します

Gemfile
gem 'trix'

その後、bundle install を実行します

bundle install

bundle installした後、app/assets/javascripts/application.js//= require trixを追加します

app/assets/javascripts/application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require activestorage
//= require trix
//= require turbolinks
//= require_tree .

次に、app/assets/javascripts/application.cssapp/assets/javascripts/application.scssにリネームして以下のように変更します

app/assets/javascripts/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */
 @import "trix";

@import "trix"; を追加しただけですね

最後に、app/views/posts/_form.html.erbapp/views/posts/show.html.erbを以下のように変更します。

app/views/posts/_form.html.erb
<div  data-controller="post">
  <div class="form-left">
    <%= form_with(model: post, local: true) do |form| %>
      <% if post.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

          <ul>
            <% post.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </ul>
        </div>
      <% end %>

      <div class="field">
        <%= form.label :title %>
        <%= form.text_field :title %>
      </div>

      <div class="field">
        <%= form.label :content %>
        <%= form.hidden_field :content, id: :content_text %>
        <trix-editor input="content_text" data-target="post.content", data-action="input->post#content"></trix-editor>
      </div>

      <div class="actions">
        <%= form.submit %>
      </div>
    <% end %>
  </div>

  <div class="form-right">
    <h1>Content</h1>
    <div data-target="post.preview"></div>
  </div>
</div>

<%= javascript_pack_tag 'application.js' %>
app/views/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @post.title %>
</p>

<p>
  <strong>Content:</strong>
  <%= sanitize @post.content, tags: %w(h1 h2 h3 h4 h5 h6 ul ol li p a img table tr td em br strong div), attributes:  %w(id class href) %>
</p>

<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>

これで、リッチなテキストエディタが使用できるようになります。

Bootstrap4の適用

このままではデザインなどが簡素すぎるのでBootstrapを使いたいと思います。

まず、Gemfilegem 'bootstrap', '~> 4.2.1'gem 'jquery-rails'を追加し、bundle installします。

Gemfile
gem 'bootstrap', '~> 4.2.1'
gem 'jquery-rails'
bundle install

もし、gemの依存関係でうまくいかない場合は、bundle updateを実行してからbundle installを実行してください

bundle update
bundle install

その後、app/assets/javascripts/application.jsapp/assets/stylesheets/application.scssを下記のように変更します

app/assets/javascripts/application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require activestorage
//= require trix
//= require jquery3
//= require popper
//= require bootstrap-sprockets
//= require turbolinks
//= require_tree .
app/assets/stylesheets/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */
 @import "trix";
 @import "bootstrap";

その後、config/boot.rbを以下のように修正します

config/boot.rb
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

ENV['EXECJS_RUNTIME'] = 'Node'

require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

これでBootstrapが使用できるようになりました。

最後に、app/views/layouts/_header.html.erbを作成し、app/views/layouts/application.html.erbでパーシャルとして呼び出します。

app/views/layouts/_header.html.erb
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <%= link_to "Stimulus", root_path, class: "navbar-brand" %>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="dropdown">
    <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      Menu
    </button>
    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
      <%= link_to 'Posts', posts_path, class: "dropdown-item" %>
    </div>
  </div>
</nav>
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Stimulus</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= render 'layouts/header'%>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>

foreman start -f Procfile.devでサーバを起動し、ナビゲーションバーが表示されていればOKです。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2