Tải Video với Rails và Ziggeo (phần 3)
Chuẩn bị và tạo Video Callbacks được cấu hình cho mỗi ứng dụng, vì thế khi mở trang tổng quan, bạn chọn một ứng dụng và click vào Manage > Web Hooks . Ở đây nhập một URL và chọn "JSON encoding" từ dropdown. Bây giờ các sự kiện sẽ được chuyển tiếp tới /api/videocallbacks dưới dạng POST ...
Chuẩn bị và tạo Video
Callbacks được cấu hình cho mỗi ứng dụng, vì thế khi mở trang tổng quan, bạn chọn một ứng dụng và click vào Manage > Web Hooks. Ở đây nhập một URL và chọn "JSON encoding" từ dropdown. Bây giờ các sự kiện sẽ được chuyển tiếp tới /api/videocallbacks dưới dạng POST request. Dưới đây là danh sách tất cả callbacks mà bạn có thể sử dụng. Lưu ý rằng không phải tất cả các sự kiện được chuyển tiếp - chỉ những cái quan trọng nhất.
Trước hết, tạo một model mới là Video, bao gồm các trường sau:
- uid (string, indexed, unique) – token của video
- user_id (integer, indexed) – khóa ngoài quan hệ giưa 1 user và 1 video
- duration (decimal) – thời gian của video tính theo giây
- ziggeo_created_at (datetime) –thời gian video đươc tạo bằng Ziggeo
- approved (boolean, indexed) – video được thêm bởi người kiểm duyệt, mặc định là false
Tạo migration:
$ rails g model Video user:belongs_to uid:string duration:decimal ziggeo_created_at:datetime approved:boolean
db/migrate/xyz/createvideos.rb
# ... create_table :videos do |t| t.string :uid t.belongs_to :user, foreign_key: true t.decimal :duration, scale: 2, precision: 5 t.datetime :ziggeo_created_at t.boolean :approved, default: false t.timestamps end add_index :videos, :approved add_index :videos, :uid, unique: true
$ rails db:migrate
Thiết lập quan hệ và validation:
models/user.rb
# ... has_many :videos, dependent: :destroy
models/video.rb
# ... belongs_to :user validates :uid, presence: true, uniqueness: true
Giờ thêm 1 route mới :
config/routes.rb
namespace :api do resources :video_callbacks, only: [:create] end
Tạo một controller trong folder api:
controllers/api/videocallbackscontroller.rb
class Api::VideoCallbacksController < ActionController::Base def create end end
Khi có một sự kiện mới đến, param eventtype thiết lập một số giá trị. Hiện tại chúng ta sẽ quan tâm đến sự kiện video_ready. Cho phép lấy dữ liệu của video và tạo một bản ghi mới dựa trên nó:
controllers/api/videocallbackscontroller.rb
class Api::VideoCallbacksController < ActionController::Base def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) end end end end
Dữ liệu video được lưu key ['data']['video'].
Respond trả về status 204 (không nội dung) nếu mọi thứ OK, hoặc 500 (lỗi máy chủ) nếu có lỗi:
controllers/api/videocallbackscontroller.rb
def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) end format.html { @result ? head(:no_content) : head(500) } end end
Thêm class method from_api. Cần tìm user dựa trên thẻ của video (hãy nhớ rằng chúng ta đang sử dụng UID của user như một thẻ) và tạo một bản ghi mới thuộc về user đó:
models/video.rb
# ... def self.from_api(data) user = User.find_by(uid: data['tags'][0]) video = user.videos.find_or_initialize_by(uid: data['token']) video.ziggeo_created_at = Time.at(data['created']) video.duration = data['duration'] video.save end
Tôi đã nhận thấy rằng đôi khi một sự kiện có thể được gửi hai lần, do đó sử dụng find_or_initialize_by để tránh tạo bản ghi trùng lặp. Vâng, điều này sẽ không thể xảy ra được khi đặt uid là duy nhất, nhưng vẫn còn.
Video Approval
Khi một video được phê duyệt hoặc từ chối bởi người kiểm duyệt, sự kiện tương ứng cũng được gửi. Chúng ta sẽ làm việc với loại sự kiện video_approve. Khi có sự kiện, tìm video trong cơ sở dữ liệu dựa trên uid và đặt thuộc tính approved thành true:
controllers/api/video_callbacks_controller.rb
def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) else if type == 'video_approve' video = Video.find_by(uid: params['data']['video']['token']) video.approve! if video else true end end format.html { @result ? head(:no_content) : head(500) } end end
Chúng ta gán true cho biến @result nếu sự kiện là loại khác. Đây là phương thức approve! :
models/video.rb
# ... def approve! self.approved = true self.save end
Video Deletion
Một video có thể bị xóa bằng bảng điều khiển Ziggeo. Khi điều đó xảy ra, chúng ta cũng muốn xóa video này khỏi cơ sở dữ liệu của mình. Loại sự kiện mà chúng tôi quan tâm được gọi là video_delete. Một lần nữa, tìm video thích hợp và sau đó chỉ cần xóa nó:
controllers/api/videocallbackscontroller.rb
# ... def create type = params['event_type'] respond_to do |format| @result = if type == 'video_ready' Video.from_api(params['data']['video']) else if type == 'video_approve' || type == 'video_delete' video = Video.find_by(uid: params['data']['video']['token']) if video type == 'video_approve' ? video.approve! : video.destroy end else true end end format.html { @result ? head(:no_content) : head(500) } end end
Tốt! Giờ chúng ta có những callback, action index trong VideosController có thể được viết lại.
Chúng ta không cần dùng Ziggeo nữa tronga action index nữa. Thay vào đó, chỉ cần lấy các video của người dùng hiện tại - chỉ những video đã được phê duyệt:
videoscontroller.rb
# ... def index @videos = current_user.videos.where(approved: true) end
Mỗi video giờ có thêm thông tin meta, chúng ta cũng có thể hiển thị nó trên trang chính:
views/videos/video.html.erb
<div class="card"> <div class="card-block"> <ziggeo ziggeo-video='<%= video.uid %>' ziggeo-awidth="320" ziggeo-height="240" ziggeo-popup> </ziggeo> <p> <strong>Duration:</strong> <%= video.duration %>s<br> <strong>Created:</strong> <%= video.ziggeo_created_at %> </p> </div> </div>
Phần cuối cùng của chức năng mà chúng tôi sẽ code hôm nay là khả năng xóa một video từ ứng dụng của chúng ta. Chỉ người dùng sở hữu video mới có thể thực hiện hành động này.
Đầu tiên, thêm link "delete":
views/videos/video.html.erb
<ziggeo ziggeo-video='<%= video.uid %>' ziggeo-awidth="320" ziggeo-height="240" ziggeo-popup> </ziggeo> <!-- ... --> <p><%= link_to 'Delete', video_path(video.uid), method: :delete %></p>
Chú ý rằng tôi đang truyền một uid của video, không phải id - chúng tôi sẽ không thực sự xóa video khỏi cơ sở dữ liệu.
In order to remove a video, a Ziggeo API client is needed. The deletion is performed using the delete method that accepts a uid. Để xóa video, cần phải có khách hàng API Ziggeo. Xoá bỏ được thực hiện bằng cách sử dụng phương pháp xóa chấp nhận một uid.
videoscontroller.rb
# ... def destroy video = current_user.videos.find_by(uid: params[:id]) if video ziggeo = Ziggeo.new(ENV['ZIGGEO_KEY'], ENV['ZIGGEO_SECRET'], ENV['ZIGGEO_ENCRYPTION']) ziggeo.videos.delete(video.uid) flash[:success] = 'Video removed! It may take some time to reflect changes on the website.' else flash[:warning] = 'Cannot find such video...' end redirect_to root_path end
Chúng ta chỉ xóa video khỏi Ziggeo. Sau khi hoàn thành, sự kiện video_delete sẽ được gửi đến callback của chúng ta và bản ghi tương ứng sẽ bị xóa khỏi cơ sở dữ liệu. Quá trình này không phải là ngay lập tức, đó là lý do tại sao chúng tôi cảnh báo người dùng rằng có thể mất một thời gian để phản ánh sự thay đổi.
Cuối cùng cũng đã kết thúc bài viết này, Ziggeo còn nhiều tính năng thú vị khác, chúng ta mới chỉ thảo luận về các tính năng cơ bản của nó. Hãy tìm hiểu thêm về Ziggeo và khám phá nó.
I hope you’ve enjoyed reading this article and I thank you for staying with me. Happy coding and see you!
Tài liệu dịch: https://www.sitepoint.com/video-uploads-with-rails-and-ziggeo/