하나의 게시물로 여러 이미지를 미리보기하면서 저장
개요
Rails 어플리케이션에서, 투고에 첨부되는 화상을 복수장, 프리뷰 표시시키면서 투고할 수 있는 기능을 구현했으므로 비망록으로서 정리합니다.
제품에 여러 개의 이미지가 붙습니다.
하나의 트윗으로 여러 이미지를 게시할 수 있는 이미지입니다.
뷰의 곳은 특히 더 좋은 방법이 있을 것이라고 생각하고 있습니다만,
개선점이나 실수가 있으면 꼭 코멘트하실 수 있으면 다행입니다!
완성 이미지
도입한 젬
· carrierwave
・mini_magick
마이그레이션
마이그레이션은 평소대로 ...
class CreateProducts < ActiveRecord::Migration[5.2]
def change
create_table :products do |t|
t.string :name, null: false
t.timestamps
end
end
end
class CreateImages < ActiveRecord::Migration[5.2]
def change
create_table :images do |t|
t.string :image
t.references :product, null: false, foreign_key: true
t.timestamps
end
end
end
모델
accepts_nested_attributes_for에서 "Product에 연결되는 Image"라는 중첩 관계를 만들 수 있습니다.
class Product < ApplicationRecord
has_many :images, dependent: :destroy
accepts_nested_attributes_for :images
end
optional : true는 외래 키 nil을 허용하는 역할.
class Image < ApplicationRecord
belongs_to :product, optional: true
mount_uploader :image, ImageUploader
end
컨트롤러
build는 new와 같은 역할입니다.
_attibutes를 사용하여 Product의 params에서 일괄 받을 수 있도록 작성합니다.
class ProductsController < ApplicationController
def new
@product = Product.new
@image = @product.images.build
end
def create
@product = Product.new(product_params)
if @product.save
params[:images]["image"].each do |image|
@image = @product.images.create!(image: image)
end
redirect_to root_path
else
@product.images.build
render action: 'new'
end
end
private
def product_params
params.require(:product).permit(:name, images_attributes: [:name]).merge(user_id: current_user.id)
end
end
보기
이번에는 최대 3장까지 했습니다.
화상수가 많아지면 쓰는 방법은 더 궁리하는 것이 좋을까라고 생각하고 있습니다・・・
fields_for를 사용하면 form_for 내에서 다른 모델에 저장할 수 있습니다.
= form_with(model: @product, local: true) do |f|
.upload__box__head
出品画像
%p.upload__box__head__sub
最大3枚までアップロードできます
.upload__box__images
= f.fields_for :images do |i|
.upload__box__image
%label{for: "image1"}
= image_tag "pict/item_upload_dummy.png", alt: "Item upload dummy" ,height: "100%", width: "100%", id: "preview1", class: "preview-image"
= i.file_field :image, multiple: true, id:"image1", type: "file", accept: "image/*", onchange: "previewImage1(this);", style: "display: none;", name: "images[image][]"
.upload__box__image
%label{for: "image2"}
= image_tag "pict/item_upload_dummy.png", alt: "Item upload dummy" ,height: "100%", width: "100%", id: "preview2", class: "preview-image"
= i.file_field :image, multiple: true, id:"image2", type: "file", accept: "image/*", onchange: "previewImage2(this);", style: "display: none;", name: "images[image][]"
.upload__box__image
%label{for: "image3"}
= image_tag "pict/item_upload_dummy.png", alt: "Item upload dummy" ,height: "100%", width: "100%", id: "preview3", class: "preview-image"
= i.file_field :image, multiple: true, id:"image3", type: "file", accept: "image/*", onchange: "previewImage3(this);", style: "display: none;", name: "images[image][]"
JS
여기도 하나로 정리되는 것 같네요・・・
function previewImage1(obj){
var fileReader = new FileReader();
fileReader.onload = (function() {
document.getElementById('preview1').src = fileReader.result;
});
fileReader.readAsDataURL(obj.files[0]);
}
function previewImage2(obj){
var fileReader = new FileReader();
fileReader.onload = (function() {
document.getElementById('preview2').src = fileReader.result;
});
fileReader.readAsDataURL(obj.files[0]);
}
function previewImage3(obj){
var fileReader = new FileReader();
fileReader.onload = (function() {
document.getElementById('preview3').src = fileReader.result;
});
fileReader.readAsDataURL(obj.files[0]);
}
이상이 됩니다!
아무래도 초보자 때문에, 여기는 이렇게 쓰면 리팩토링할 수 있어! 라든지 있으면 가르쳐 주시면 감사하겠습니다!
Reference
이 문제에 관하여(하나의 게시물로 여러 이미지를 미리보기하면서 저장), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/miyomiyo344/items/956ab91f380e5c203729텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)