This time it seems that the timing of saving images has changed from Rails 6, so I checked it.
$ rails -v
Rails 6.0.2.1
$ rails active_storage:install
$ rails db:migrate
I will post the final product.
Add preview to route.
route.rb
Rails.application.routes.draw do
  resources :users do
    collection do
      post :preview
      patch :preview
    end
  end
end
Allows the model to handle images with has_one_attached.
user.rb
class User < ApplicationRecord
  has_one_attached :image
end
Next is the controller. This time I want to add a preview function, so I added a preview action.
user_controller.rb
class UsersController < ApplicationController
  before_action :set_user, only: [:show, :edit, :update, :destroy]
  # GET /users
  # GET /users.json
  def index
    @users = User.all
  end
  # GET /users/1
  # GET /users/1.json
  def show
  end
  # GET /users/new
  def new
    @user = User.new
  end
  # GET /users/1/edit
  def edit
  end
.
.
.
.
  def preview
    @user = User.new(user_params)
    image_binary = ''
    if @user.image.attached?
      image_binary = @user.attachment_changes['image'].attachable.read
    else
      saved_user = User.find_by(id: params[:id])
      if saved_user.present? && saved_user.image.attached?
        image_binary = saved_user.image.blob.download
      end
    end
    @image_enconded_by_base64 = Base64.strict_encode64(image_binary)
    render template: 'users/_preview', layout: 'application'
  end
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end
    # Only allow a list of trusted parameters through.
    def user_params
      params.require(:user).permit(:name, :image)
    end
end
Finally, html.
ruby:new.html.erb
<h1>New User</h1>
<%= render 'form', user: @user %>
<%= link_to 'Back', users_path %>
ruby:_form.html.erb
<%= form_with(model: user, local: true) do |form| %>
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
      <ul>
        <% user.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
    <%= form.label :image %>
    <%= form.file_field :image %>
  </div>
  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
ruby:show.html.erb
<p id="notice"><%= notice %></p>
<p>
  <strong>Name:</strong>
  <%= @user.name %>
  <% if @user.image.attached? %>
    <%= image_tag @user.image %>
  <% end %>
</p>
<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>
ruby:_preview.html.erb
<p id="notice"><%= notice %></p>
<p>
  <strong>Name:</strong>
  <%= @user.name %>
  <% if action_name == 'preview' %>
    <img src="data:image/png;base64,<%= @image_enconded_by_base64 %>" />
  <% else %>
    <%= image_tag @member.image %>
  <% end %>
</p>
Now you are ready.
I will upload the image immediately.
 
When you upload the test .jpeg and press the Create User button
 
create is successful. If you go to see the image uploaded here
irb(main):005:0> @user.image.attachment
  ActiveStorage::Attachment Load (1.5ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ?  [["record_id", 1], ["record_type", "User"], ["name", "image"], ["LIMIT", 1]]
=> #<ActiveStorage::Attachment id: 1, name: "image", record_type: "User", record_id: 1, blob_id: 1, created_at: "2020-05-21 09:04:12">
I found that the image exists.
Then try a new preview.
 
In the same way, upload the preview .jpg and press the preview button to check the image.
Then
> @user.image.attachment
NameError: uninitialized constant #<Class:0x00007fd450065780>::Analyzable
from /usr/local/bundle/gems/activestorage-6.0.3.1/app/models/active_storage/blob.rb:26:in `<class:Blob>'
Absent! !!
> params[:user][:image]
=> #<ActionDispatch::Http::UploadedFile:0x000055892ec2b598
 @content_type="image/jpeg",
 @headers=
  "Content-Disposition: form-data; name=\"user[image]\"; filename=\"\xE3\x83\x95\xE3\x82\x9A\xE3\x83\xAC\xE3\x83\x92\xE3\x82\x99\xE3\x83\xA5\xE3\x83\xBC.jpg\"\r\nContent-Type: image/jpeg\r\n",
 @original_filename="preview.jpg ",
 @tempfile=#<File:/tmp/RackMultipart20200522-1-ha9tz1.jpg>>
Check the parameters. Isn't it saved just by uploading the image?
If you refer to the following https://github.com/rails/rails/pull/33303
on rails5
@user.image = params[:image]
It's the timing when you put it in the attribute!
No way there is such a change in rails 6! !! If this is left as it is, the image cannot be passed to View at the time of preview (without saving the image in the instance).
When I was looking for a good way
・ Https://github.com/rails/rails/pull/33303
・ Https://stackoverflow.com/questions/57564796/reading-from-active-storage-attachment-before-save
there were!!
record.attachment_changes['<attributename>'].attachable
try!
> @user.attachment_changes['image'].attachable
=> #<ActionDispatch::Http::UploadedFile:0x000055892ec2b598
 @content_type="image/jpeg",
 @headers=
  "Content-Disposition: form-data; name=\"user[image]\"; filename=\"\xE3\x83\x95\xE3\x82\x9A\xE3\x83\xAC\xE3\x83\x92\xE3\x82\x99\xE3\x83\xA5\xE3\x83\xBC.jpg\"\r\nContent-Type: image/jpeg\r\n",
 @original_filename="preview.jpg ",
 @tempfile=#<File:/tmp/RackMultipart20200522-1-ha9tz1.jpg>>
further
@user.attachment_changes['image'].attachable.read
I was able to fetch the binary data with ↑, so if I encode it with Base64 and pass it
@image_enconded_by_base64 = Base64.strict_encode64(@user.attachment_changes['image'].attachable.read)
 
It's done! !!
I didn't know there was a change in the timing of saving Active Strage. If you want to touch the image without saving
record.attachment_changes['<attributename>'].attachable.read
Read the binary with Base64! !! (It doesn't have to be Base64)
Please let me know if there is any other good way.
Recommended Posts