Setting up Rails 5.2 Active Storage, sử dụng Google Cloud Storage và Heroku

Mục đích của tutorial này là tạo một rails app "To do", đính kèm ảnh và các tập tin khác vào Google Cloud Storage, sử dụng Rails Active Storage, cuối cùng, deploy app lên Heroku thông qua git. Chỉ cần có các kiến thức cơ bản về Rails và git, bạn hoàn toàn thể thực hiện được từng bước theo bài viết.

Đầu tiên, cần chắc chắn bạn đã cài đặt đúng version. Chúng ta cần Rails 5.2, vì từ phiên bản này mới có Active Storage, và cần Ruby từ version 2.2.2 trở lên.

rails -v
ruby -v

Và nếu tất cả đã sẵn sàng, hãy tạo một Rails app:

rails new todo-pic
cd todo-pic

Bắt đầu bằng việc tạo model Todo, controller, view và migate database:

rails generate scaffold Todo task:string
rails db:migrate

setup root trong file config/routes.rb

root "todos#index"

khởi động server

rails server

Giờ vào địa chỉ http://localhost:3000, trang web của chúng ta sẽ tựa tựa thế này:

Vậy là xong công tác chuẩn bị, tiếp theo sẽ là cách để đính kèm ảnh.

Setup Active Storage

Trong bước đầu tiên này Rails sẽ tạo 2 bảng trong database là active_storage_blobsactive_storage_attachments. Nó cũng tạo ra file config storage.yml nhưng chúng ta sẽ nói đến nó sau.

rails active_storage:install
rails db:migrate

xem code đầy đủ ở đây

Thiết lập 1 tập đính kèm

has_one_attached sẽ setup mối quan hệ 1 - 1 giữa bản ghi và file đính kèm. Mỗi bản ghi chỉ có thể chứa 1 file đính kèm. Trong ví dụ này, sẽ là 1 ảnh đính kèm với 1 todo.

Sửa lại Model:

# app/models/todo.rb
class Todo < ApplicationRecord
    has_one_attached :picture
end

Sửa lại Controller thêm param :picture

# app/controllers/todos_controller.rb
def todo_params
    params.require(:todo).permit(:task, :picture)
end

Sửa lại view: trong form, tạo một thẻ input file_field, phía trên nút submit:

# app/views/todos/_form.html.erb
...
<div class="field">
  <%= form.label :picture %>
  <%= form.file_field :picture %>
</div>
...

Trong trang show, hiển thị imge với thẻ image_tag, quy ước chiều rộng 200px, và thêm điều kiện if kiểm tra có tệp đính kèm hay không, phương thức attached? sẽ trả về true nếu có tệp đính kèm.

# app/views/todos/show.html.erb
...
<p>
  <%= image_tag(@todo.picture, width: 200) if @todo.picture.attached? %> 
</p>
...

Vậy là xong.

xem code đầy đủ ở đây

Setup nhiều tệp đính kèm

Giờ ta muốn đính kèm nhiều tập tin vào todo. has_many_attached sẽ setup mối quan hệ 1 - n giữa record và tệp đính kèm. Mỗi bản ghi có thể có nhiều tệp đính kèm.

Sửa lại model:

# app/models/todo.rb
class Todo < ApplicationRecord
    ...
    has_many_attached :uploads
end

Sửa lại controller: có nhiều tập tin nên ta phải truyền param vào dưới dạng mảng

# app/controllers/todos_controller.rb
...
def todo_params
  params.require(:todo).permit(..., uploads: [])
end
...

Sửa lại view: trong form, thêm thẻ input file_field cho phép upload nhiều file, bằng cách thêm option multiple: true

# app/views/todos/_form.html.erb
...
<div class="field">
  <%= form.label :uploads %>
  <%= form.file_field :uploads, multiple: true %>
</div>
...

Và trong trang show, chúng ta sẽ hiển thị tất cả file được upload. Nếu không có gì, message no uploads sẽ hiện ra.

# app/views/todos/show.html.erb
...
<p>
  <strong>Uploads:</strong> <br/>
  <% if @todo.uploads.attached? %>
    <% @todo.uploads.each do |upload| %>
      <%= link_to upload.filename, upload, target: '_blank' %> <br/>
    <% end %>
  <% else %>
    <p>no uploads</p>
  <% end %>
</p>
...

Vậy là xong, bạn có thể test thử upload nhiều file.

Nãy giờ, chúng ta vẫn lưu vào local, phần tiếp theo sẽ nói về cách sử dụng Google Cloud Service để lưu trữ các tập tin.

Lưu ý: trước khi sang phần sau cần xóa hết các bản ghi và tệp đính kèm vừa tạo (hoặc reset database) để tránh gặp lỗi khi sửa lại config.

xem code chi tiết ở đây

Google cloud services (GCS)

Bắt đầu bằng việc tạo 1 account, nếu bạn chưa có. Bạn có thể tạo miễn phí, và dùng thử 1 năm dịch vụ professional. Ở Console tạo project "Todo-pic" (hoặc bất kì tên gì bạn thích)

Bước tiếp theo là tạo "bucket", nơi lưu trữ dữ liệu. Click vào Storage:

Sau đó click vào Create bucket:

Giờ bạn có thể chọn một cái tên cho bucket của mình, lưu ý là nó phải là cái tên chưa từng được sử dụng trên Cloud Storage. Chọn storage class là Regional và a server zone (ví dụ us-east1), rồi ấn Create:

Bucket đã được tạo, nhưng giờ bạn cần truy cập nó. Google cung cấp sẵn API để làm điều đó, nhưng bạn cần tạo Credentials:

Chọn APIs and Services và Credentials:

Tạo ‘Service account key’ để enable giao tiếp server-to-server.

Chọn tên account. Chọn role Project/Owner, và key type JSON. Sau đó click ‘Create’.

Khi bạn click Create, private key sẽ được download về máy tính của bạn.

Giờ bắt đầu setup Rails app để làm việc với Google Cloud Bucket. Bắt đầu bằng cách tạo folder secrets trong folser config/. Sau đó thêm /config/secrets/* vào file .gitignore. Nó sẽ ngăn chặn việc folder secrets bị upload lên git remote.

Tiếp theo di chuyển file .json vừa download về vào folder config/secrets/. Đổi tên nó thành todo-pic.json.

Mở file config/storage.yml, đây là file lưu trữ các config, bạn có thể thấy service test:local: được lưu làm mặc định. Thêm config service google:, sử dụng tên project và bucket của bạn.

# config/storage.yml
google:
  service: GCS
  project: todo-pic
  credentials: <%= Rails.root.join("config/secrets/todo-pic.json") %>
  bucket: todo-pic-pjbelo

Giờ sửa file config/environments/development.rb để Rails biết bạn muốn sử dụng google: ở môi trường development.

# config/environments/development.rb
config.active_storage.service = :google

Chúng ta cần thêm gem google-cloud-storage vào gemfile làm thư viện cho Google Cloud Storage.

#Gemfile
gem "google-cloud-storage", "~> 1.8", require: false

và chạy bundle install.

Giờ mọi thứ đã sẵn sàng! Chạy server và test thử tính năng upload. Bạn có thể check trong Google Cloud Platform / Bucket số lượng file được upload.

xem code chi tiết ở đây

Heroku

Hãy bắt đầu bằng việc tạo 1 account, nếu bạn chưa có. Sau đó cài Heroku CLI.

Sửa lại file config/environments/production.rb để nói cho hệ thống bạn muốn sử dụng google: ở môi trường production.

config.active_storage.service = :google

Login vào Heroku bằng cách chạy lệnh heroku login.

Config database

Phần mềm quản lý database mặc định của Rails là SQLite, nhưng Heroku không làm việc với nó. Heroku khuyên nên sử dụng PostgreSQL và nên sử dụng cùng 1 loại phần mềm quản lý database cho môi trường development và production, hạn chế những bug phát sinh do khác biệt giữa các phần mềm. Trong bài viết này thì vẫn sử dụng SQLite ở môi trường development, nhưng đừng làm vậy ở dự án thực tế nhé.

Để sử dụng PostgreSQL ở môi trường production thì phải thêm vào Gemfile:

#Gemfile
group :production do
  gem 'pg'
end

Và dời development và test vào cùng 1 group:

group :development, :test do
  # Use sqlite3 as the database for Active Record
  gem 'sqlite3'
  ...

sau đó lại chạy bundle install.

Ngoài việc sử dụng gem pg, chúng ta còn phải config các biến database của Heroku, và đảm bảo file config/database.yml sử dụng adapter postgresql:

# config/database.yml
production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

Xem code đầy đủ ở đây.

Tạo app Heroku

Phải chắc chắn bạn đang ở trong folder có chứa Rails app, sau đó tạo app Heroku, tên bạn chọn phải chưa từng được sử dụng trên Heroku.

heroku create todo-pic-pjbelo

Sửa Credentials

Chạy lệnh sau để tạo biến môi trường RAILS_MASTER_KEY với nội dung trong config/master.key cho Heroku: heroku config:set RAILS_MASTER_KEY="$(< config/master.key)"

Thêm config Google Credentials vào Heroku: heroku config:set GOOGLE_APPLICATION_CREDENTIALS="$(< config/secrets/todo-pic.json)".

Bạn có thể kiểm tra biến môi trường ở Heroku bằng lệnh: heroku config.

Sử dụng Rails Credentials

Nếu bạn không hứng thú với việc sử dụng Rails Credentials, bạn có thể chuyển thẳng sang phần sau là "Deploy App Heroku với Git".

Sử dụng Rails Credentials bạn sẽ không phải lo lắng về file key trên server production vì nó sẽ bị mã hóa, và bạn cũng không phải lo đến việc setting biến môi trường. Mở config/todo-pic.json và copy tất cả nội dung.

Sửa rails credentials: rails credentials:edit.

Thêm tên cho hash là gcs_todo_pic: và dán toàn bộ nội dụng của file json vào. Đây là cách để 1 cái hash vào rails credentials. Sau đó lưu lại.

Bạn có thể kiểm tra bằng cách chạy:

rails console
puts Rails.application.credentials.gcs_todo_pic

Tiếp theo, sửa config storage.yml:

# config/storage.yml
...
google:
  service: GCS
  project: todo-pic
  credentials: <%= Rails.application.credentials.gcs_todo_pic.to_json %>
  bucket: todo-pic-pjbelo
...

Phương thức to_json sẽ convert định dạng từ hash thành json.

Deploy app Heroku với git

Nếu chưa commit thì nhớ add và commit các thay đổi vào, sau đó push lên Heroku:

git add
git commit -m 'init'
git push heroku master

Cuối cùng chạy migrate database: heroku run rake db:migrate

Chúc mừng!!!

Bạn đã deploy thành công Todo App với các tệp đính kèm trong Google Cloud. Kiểm tra tại: http://<your-app-name>.herokuapp.com.

Hy vọng bài viết có ích với bạn. Cảm ơn đã theo dõi!

Nguồn: https://medium.com/@pjbelo/setting-up-rails-5-2-active-storage-using-google-cloud-storage-and-heroku-23df91e830f8


All Rights Reserved