# Rails專案使用ActiveStorage連接S3資料庫 Active Storage 可以支援各種後端服務(如 AWS S3),為 Active Record 模型提供檔案上傳和附件功能。 # ## 前置作業 * 先建立一個新專案來測試 `$ rails new project_name` * 為專案安裝Active Storage功能,會在資料庫中建立兩個名為 active_storage_blobs 和 active_storage_attachments 的資料表 `$ rails active_storage:install` * 用scaffold建立一個用來上傳的model取名為Upload `$ rails generate scaffold Upload` * 將表格具現化 `$ rails db:migrate` --- ## 設定ActiveStorage * 在upload.rb寫上,讓model有上傳功能 ``` class Upload < ApplicationRecord has_one_attached :file end ``` * 在uploads_controller.rb建立create 方法 ``` def create @upload = Upload.new() @upload.file.attach(params[:upload][:file]) @upload.save! redirect_back(fallback_location: root_path) end ``` * 在config/storage.yml添加S3的設定 ``` amazon: service: S3 access_key_id: "S3的access_key_id" secret_access_key: "S3的secret_access_key" bucket: "S3貯體名稱" region: "S3n所在區域" # e.g. 'us-east-1' ``` * 在config/environments/production.rb進行設定至amazon `config.active_storage.service = :amazon` * 在Gemfile加上S3套件 `gem "aws-sdk-s3", '~> 1.87', require: false` * 安裝套件 `$ bundle install` * 修改_form.html.erb ``` <%= form_with(model: upload) do |form| %> <div class="form-group"> <%= form.file_field :file %><br> </div> <div class="actions"> <%= form.submit %> </div> <% end %> ``` * 避免金要上傳,安裝fiagro `gem 'figaro', '~> 1.0'` * 生成需要的application.yml,這個檔案不會被上傳至github `$ figaro install` * 修改storage.yml中的amazon設定 ``` amazon: service: S3 access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %> secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %> bucket: <%= ENV["AWS_BUCKET"] %> region: <%= ENV["AWS_REGION"] %> ``` * 將實際的金鑰寫入application.yml ``` amazon: AWS_ACCESS_KEY_ID: "S3的access_key_id" AWS_SECRET_ACCESS_KEY: "S3的secret_access_key" AWS_BUCKET: "S3貯體名稱" AWS_REGION: "S3n所在區域" ``` * 將上傳功能把從本機上傳檔案改成從url儲存圖片,這裡先直接塞圖片網址來測試,修改create ``` def create require 'open-uri' file = open("https://oawan.me/img/program/rvm-logo-all-happy.png") @upload = Upload.new() @upload.file.attach(io: file, filename: 'some-image.jpg') @upload.save! redirect_back(fallback_location: root_path) end ``` * 利用js抓取頁面圖片url來作為儲存目標,先在new頁面放一張圖並給予id `<img id= "picture" src="https://oawan.me/img/program/rvm-logo-all-happy.png">` * 在_form.html.erb,給form一個btn的class標籤,並將原本的輸入欄位改成隱藏欄位並給予一個class名稱add-src,src為儲存js抓取到的url的欄位 ``` <div class="btn"> <%= form_with(model: upload) do |form| %> <div class="form-group"> <%= form.hidden_field :src, value: "", class: 'add-src' %><br> </div> <div class="actions"> <%= form.submit %> </div> <% end %> </div> ``` * 為uploads增加一個名為src的新欄位 * 在app/javascript/packs新增upload.js ``` window.addEventListener('turbolinks:load', function() { const btn = document.querySelector('.btn') const pic = document.getElementById('picture') const form = document.querySelector("form") let inputValue = document.querySelector('.add-src') console.log(inputValue) btn.addEventListener('click', function(){ inputValue.setAttribute("value", pic.src) }) }) ``` * 在app/javascript/packs/application.js中引入upload.js `import "./upload"` * 最後因為我們要抓取網頁中的圖片來儲存,所以將create修改 ``` def create require 'open-uri' url = params[:upload][:src] file = open(url) @upload = Upload.new(upload_params) @upload.file.attach(io: file, filename: 'some-image.jpg') @upload.save! redirect_back(fallback_location: root_path) end ``` * 清洗params ``` private def upload_params params.require(:upload).permit(:src) end ``` --- ## 部署至Heroku進行測試 * 接著部署至Heroku,可以看到用scaffold做出的畫面 * 選擇文章的截圖上傳   * 再到Amazon S3,就可以看到檔案已經上傳  * 打開檔案來確認,確認是所上傳的截圖,到這裡基本上專案已經有上傳檔案至S3的功能  * 目前的設定只能在部署上線後傳檔案至S3,如果在開發環境也想要上傳S3,只要將/Users/ryan/ss3/config/environments/development.rb中的`config.active_storage.service = :local`改成`config.active_storage.service = :amazon`即可
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up