Tạo ứng dụng Rails với database có sẵn
Bài đăng này đã không được cập nhật trong 3 năm
Trong bài viết lần này, mình sẽ giới thiệu với các bạn cách tạo một Rails app với một database có sẵn. Điều này rất có ích trong một số trường hợp như: bỗng nhiên bạn muốn thay đổi ứng dụng của mình được viết bằng Rails trong khi trước đó đang viết trên 1 nền tảng khác, hoặc trong trường hợp thiết kế một ứng dựng đa nền tảng sử dụng chung một database có sẵn.
Bắt đầu nào
Giả sử bạn có 2 bảng dữ liệu là NguoiDung và BaiViet như sau:
Nó được việt hóa hoàn toàn và không tuân thủ theo quy tắc đặt tên của Rails Tới đây bạn bắt đầu manh nha suy nghĩ thôi tạo lại DB từ đầu cho dễ chơi dễ trúng thưởng. Nhưng mà khoan, như thế thì mất hết dữ liệu à. Thôi thử làm tiếp xem sao
Tạo mới Rails app
Lại thấy easy rồi
Ở đây DB của mình sử dụng là MySQL nên sẽ thêm gem 'mysql2'
vào và bundle install
để cài đặt một số gem cần thiết
Thủ tục cuối cùng là config DB, tìm đến file config/database.yml và cấu hình đến database của bạn
development:
adapter: mysql2
encoding: utf8
database: test_db
pool: 5
username: *****
password: *****
host: 127.0.0.1
port: 3306
Kéo data về với bản làng
Mọi thứ dường như đã sẵn sàng, công việc cuối cùng là làm thế nào để Rails ActiveRecord có thể tương tác với DB để nó làm việc mai mối còn chúng ta chỉ việc code Ruby và không cần quan tâm tới sự đời. Theo cách bình thường, bạn sẽ tạo các file migration, chạy lệnh migrate để generate ra schema, tạo model và code. Nhưng mà khoan, chúng ta có DB có sẵn mà nhỉ Rails nó có lệnh dump để tạo ra schema kết nối với database đã config
rails db:schema:dump
Với database lúc nãy, mình sẽ có file schema.rb như sau:
Tạo model
Bây giờ hãy tạo 2 model đại diện cho 2 cái bảng trong DB mà mình vừa dump về nhé. Ồ, table tiếng việt à, thế thì model cũng để tiếng việt luôn cho nó khác người
models/nguoi_dung.rb
class NguoiDung < ApplicationRecord
end
models/bai_viet.rb
class BaiViet < ApplicationRecord
end
Thử rails c xem lấy được dữ liệu không nào
2.4.0 :001 > NguoiDung.first
(0.3ms) SET NAMES utf8, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
NguoiDung Load (0.5ms) SELECT `nguoi_dungs`.* FROM `nguoi_dungs` ORDER BY `nguoi_dungs`.`id` ASC LIMIT 1
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'test_db.nguoi_dungs' doesn't exist: SELECT `nguoi_dungs`.* FROM `nguoi_dungs` ORDER BY `nguoi_dungs`.`id` ASC LIMIT 1
from (irb):1
2.4.0 :002 >
Như các bạn đã thấy, theo quy tắc của rails thì model NguoiDung nó sẽ select đến bảng nguoi_dungs, mã tất nhiên trong DB của chúng ta chỉ có bảng NguoiDung chứ làm gì có nguoi_dungs để nó truy vấn. Vậy thì hơi mệt một chút, trót lấy DB không theo quy tắc của Rails thì phải mất công ngồi config thêm xí nữa. Hãy khai báo cho Rails biết model của bạn đang đại diện cho bảng nào trong CSDL
class NguoiDung < ApplicationRecord
self.table_name = "NguoiDung"
end
Kết quả:
2.4.0 :005 > NguoiDung.first
NguoiDung Load (0.2ms) SELECT `NguoiDung`.* FROM `NguoiDung` ORDER BY `NguoiDung`.`MaNguoiDung` ASC LIMIT 1
=> #<NguoiDung MaNguoiDung: 1, TenNguoiDung: "Da xua">
2.4.0 :006 >
Cùng config thêm mấy cái quan hệ nào
models/nguoi_dung.rb
class NguoiDung < ApplicationRecord
self.table_name = "NguoiDung"
has_many :bai_viet, class_name: BaiViet.name, foreign_key: "MaNguoiDung"
end
models/bai_viet.rb
class BaiViet < ApplicationRecord
self.table_name = "BaiViet"
belongs_to :nguoi_dung, class_name: NguoiDung.name, foreign_key: "MaNguoiDung"
end
rails c ra và kết quả là
2.4.0 :022 > NguoiDung.first.bai_viet
NguoiDung Load (0.2ms) SELECT `NguoiDung`.* FROM `NguoiDung` ORDER BY `NguoiDung`.`MaNguoiDung` ASC LIMIT 1
BaiViet Load (0.3ms) SELECT `BaiViet`.* FROM `BaiViet` WHERE `BaiViet`.`MaNguoiDung` = 1 LIMIT 11
=> #<ActiveRecord::Associations::CollectionProxy [#<BaiViet MaBaiViet: 1, TieuDe: "15gg", NoiDung: "Hasagi", MaNguoiDung: 1>, #<BaiViet MaBaiViet: 2, TieuDe: "20gg", NoiDung: "Death is like the wind, always by my site", MaNguoiDung: 1>]>
2.4.0 :023 > BaiViet.first.nguoi_dung
BaiViet Load (0.7ms) SELECT `BaiViet`.* FROM `BaiViet` ORDER BY `BaiViet`.`MaBaiViet` ASC LIMIT 1
NguoiDung Load (0.6ms) SELECT `NguoiDung`.* FROM `NguoiDung` WHERE `NguoiDung`.`MaNguoiDung` = 1 LIMIT 1
=> #<NguoiDung MaNguoiDung: 1, TenNguoiDung: "Da xua">
2.4.0 :024 >
Chúc các bạn thành công!
All rights reserved