Railsにこれから初めて触れる方を対象にしたチュートリアルです
Trixに画像アップロード機能を作るチュートリアルになります
まず、rails newを実行し、Railsアプリのひな型を作成します
rails new trix_image
次に、作成したRailsアプリのディレクトリへと移動します
cd trix_image
先ほどのrails newでsqlite3のインストールがエラーになっている場合は、以下のようにバージョンを修正します
gem 'sqlite3', '1.3.13'
その後、bundle installを実行します
bundle install
rails g scaffold コマンドを使い、Trixで使用するCRUDを作成します
rails g scaffold post title:string content:text auther:string
次に、画像投稿用のCRUDを作成します
rails g scaffold photo image
その後、rails db:migrateでマイグレーションを行います
rails db:migrate
Trixを導入していきます
まずはGemfileにTrixを追加します
gem 'trix'
その後、bundle installを実行します
bundle install
次に、app/assets/javascripts/application.jsに以下の行を追加します
//= require trix
また、app/assets/stylesheets/application.cssにも以下の行を追加します
*= require trix
app/views/posts/_form.html.erbを以下のように変更します
<%= 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: 'post_content' %>
    <trix-editor input="post_content"></trix-editor>
  </div>
  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
最後に、app/view/posts/show.html.erbを以下のように変更します
<p id="notice"><%= notice %></p>
<p>
  <strong>Title:</strong>
  <%= @post.title %>
</p>
<p>
  <strong>Content:</strong>
  <%= sanitize @post.content %>
</p>
<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
Shrineというアップロード用のgemを使用し、画像アップロード機能のひな型を作成します
まず、GemfileにShrineを追加します
gem 'shrine'
その後、bundle installを実行します
bundle install
その後、config/initializers/shrine.rbを以下のように作成します
require "shrine"
require "shrine/storage/file_system"
Shrine.storages = {
  cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"),
  store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store"),
}
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data
次に、app/views/photos/_photo.json.jbuilderに以下の一行を追加します
json.image_url photo.image_url 
アップロード用のモデルapp/models/image_uploader.rbを作成します
class ImageUploader < Shrine
end
作成したモデルをPostモデルにincludeします
class Photo < ApplicationRecord
    include ImageUploader[:image]
end
rails g migrationコマンドを使用して既存のimageカラムをimage_dataカラムにリネームします
rails g migration RenameImageColumnToPhotos
作成したマイグレーションファイルを以下のようにします
class RenameImageColumnToPhotos < ActiveRecord::Migration[5.2]
  def change
    rename_column :photos, :image, :image_data
  end
end
rails db:migrateを実行し、マイグレーションを行います
rails db:migrate
後は、app/views/photos/_form.html.erbを編集し、アップロードができるようにします
<%= form_with(model: photo, local: true) do |form| %>
  <% if photo.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(photo.errors.count, "error") %> prohibited this photo from being saved:</h2>
      <ul>
      <% photo.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= form.label :image %>
    <%= form.file_field :image, id: :photo_image %>
  </div>
  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
これで、画像のアップロードが実行できるようになりました
app/assets/javascripts/application.jsを以下のように修正します
  
   function uploadAttachment(attachment) {
    var file = attachment.file;
    var form = new FormData;
    form.append("Content-Type", file.type);
    form.append("photo[image]", file);
  
    var xhr = new XMLHttpRequest;
    xhr.open("POST", "/photos.json", true);
    xhr.setRequestHeader("X-CSRF-Token", Rails.csrfToken());
  
    xhr.upload.onprogress = function(event) {
      var progress = event.loaded / event.total * 100;
      attachment.setUploadProgress(progress);
    }
  
    xhr.onload = function() {
      if (xhr.status === 201) {
        var data = JSON.parse(xhr.responseText);
        return attachment.setAttributes({
          url: data.image_url,
          href: data.url
        })
      }
    }
  
     return xhr.send(form);
  }
  
   // Listen for the Trix attachment event to trigger upload
  document.addEventListener("trix-attachment-add", function(event) {
    var attachment = event.attachment;
    if (attachment.file) {
      return uploadAttachment(attachment);
    }
  });
これで、エディターに画像をペーストするだけで画像のアップロードができるようになります!