- Ruby on Rails là gì? Triết lý thiết kế cốt lõi của framework là gì?
Ruby on Rails (Rails) là web framework viết bằng Ruby, do David Heinemeier Hansson (DHH) tạo ra năm 2004. Rails nổi tiếng với hai triết lý cốt lõi: - Convention over Configuration (CoC): Rails đặt ra quy ước mặc định — tên file, tên bảng…
- Giải thích kiến trúc MVC trong Rails.
Rails chia ứng dụng thành 3 tầng: Tầng Trách nhiệm Ví dụ --------- Model Dữ liệu + business logic; giao tiếp DB qua Active Record app/models/user.rb View Trình bày HTML cho người dùng (ERB/Haml/Slim) app/views/users/show.html.erb Controller Nhận request, gọi model, chọn view để render app/controllers/userscontroller.rb…
- Cấu trúc thư mục của một Rails app chuẩn trông như thế nào?
Các thư mục quan trọng cần biết: CoC quy định: model User → file app/models/user.rb → bảng DB users. Không cần khai báo mapping — Rails suy ra từ tên.
- Gem là gì trong hệ sinh thái Ruby/Rails?
Gem là thư viện (package) Ruby được phân phối qua RubyGems.org. Bản thân Rails cũng là một gem. Trong project, dependency được khai báo trong Gemfile và do Bundler quản lý. Gemfile.lock lưu chính xác phiên bản đang dùng — commit file này vào git…
- `resources` trong Rails Router làm gì? Nó tạo ra những route nào?
resources :posts tự động tạo 7 route RESTful chuẩn: HTTP Verb Path Action Helper ------------ GET /posts index postspath GET /posts/new new newpostpath POST /posts create postspath GET /posts/:id show postpath(id) GET /posts/:id/edit edit editpostpath(id) PATCH/PUT /posts/:id update postpath(id) DELETE /posts/:id destroy postpath(id) Dùng only:…
- Phân biệt `render` và `redirect_to` trong Rails Controller.
render dựng view ngay trong request hiện tại — không tạo request mới, URL giữ nguyên, instance variables vẫn còn. redirectto gửi HTTP 302, bảo browser tạo request mới đến URL khác — controller hiện tại kết thúc, action mới chạy từ đầu. Lỗi thường…
- Before action (`before_action`) trong Rails dùng để làm gì?
beforeaction là callback chạy trước một hoặc nhiều action của controller — dùng để factoring logic dùng chung (authentication, authorization, load record). Nếu beforeaction gọi render hoặc redirectto, chuỗi callback dừng và action gốc không chạy. Các loại khác: afteraction, aroundaction.
- Nested resources trong Rails là gì? Khi nào nên dùng?
Nested resources biểu diễn quan hệ cha-con trong URL: /posts/:postid/comments — comment luôn thuộc về 1 post cụ thể. Route được tạo: GET /posts/:postid/comments, POST /posts/:postid/comments, ... Trong CommentsController, lấy post qua Post.find(params[:postid]) rồi build comment từ @post.comments. Best practice: chỉ nest 1 cấp —…
- Strong Parameters trong Rails là gì và tại sao cần thiết?
Strong Parameters (Rails 4+) bắt controller khai báo tường minh những tham số nào được phép gán vào model — ngăn mass assignment vulnerability (attacker gửi param ẩn như admin=true để leo quyền). Nếu params chứa field không được permit, nó bị bỏ qua. Nếu…
- Active Record là gì? Rails mapping tên model với bảng DB như thế nào?
Active Record là ORM (Object-Relational Mapper) của Rails — mỗi model Ruby class tương ứng với 1 bảng DB, mỗi instance tương ứng với 1 row. Quy ước đặt tên (CoC): Model class Bảng DB ------ User users BlogPost blogposts OrderItem orderitems Model tự hiểu…
- Các loại associations (quan hệ) trong Active Record là gì?
Active Record hỗ trợ 6 loại association: Quy tắc foreign key: belongsto bên nào thì bảng đó chứa foreign key. hasmany :through (3 bảng) dùng khi join table cần thêm attributes. hasandbelongstomany (2 bảng) dùng khi join table thuần tuý không cần id/attrs.
- N+1 Query là gì và Rails giải quyết bằng cách nào?
N+1 xảy ra khi load 1 collection rồi lặp để lấy association của mỗi item → 1 query lấy list + N query cho từng item. includes vs eagerload vs preload: - includes → Rails tự chọn strategy (preload hoặc eagerload). - preload → luôn…
- Validations trong Active Record — các validation phổ biến nhất là gì?
Validations chạy trước save / create / update. Nếu fail, record không được lưu và lỗi nằm trong record.errors. Dùng save! / create! để raise ActiveRecord::RecordInvalid thay vì trả false — tốt hơn trong business logic cần fail-fast.
- Active Record Callbacks là gì? Liệt kê các callback quan trọng.
Callbacks là hooks vào lifecycle của model — chạy tự động khi object được create/update/destroy. Thứ tự khi save một record mới: aftercommit chạy sau khi transaction commit — dùng cho side-effects (gửi mail, enqueue job). Dùng aftersave có thể gửi mail dù transaction sau…
- Scopes trong Active Record là gì? Khi nào dùng scope thay vì class method?
Scope là named query được định nghĩa trong model, trả về ActiveRecord::Relation → chainable. Scope vs class method: scope luôn trả về ActiveRecord::Relation (kể cả khi condition false → trả toàn bộ). Class method có thể trả nil → chain bị gãy. Với logic phức…
- `find`, `find_by` và `where` khác nhau như thế nào?
- Migrations trong Rails là gì? Tại sao cần dùng thay vì viết SQL trực tiếp?
Migration là Ruby class mô tả thay đổi schema DB theo thời gian — có thể chạy lên (up/change) hoặc rollback xuống (down). Tại sao không viết SQL trực tiếp: - Version control được (mỗi migration là 1 file commit-able). - Portable: change method tự…
- `db/schema.rb` là gì? Khác gì với các migration files?
db/schema.rb là snapshot toàn bộ schema hiện tại — được Rails tự sinh sau mỗi lần db:migrate. Nó không phải migration, mà là trạng thái cuối cùng của DB. Tại sao quan trọng: - rails db:schema:load tạo DB mới từ schema.rb (nhanh hơn replay toàn…
- Khi nào dùng `change` và khi nào cần viết `up`/`down` riêng trong migration?
change dùng cho các operations tự reversible — Rails biết cách đảo ngược: Một số operations không reversible → phải viết up/down rõ ràng: Operations không reversible: removecolumn (mất data type), changecolumn, execute raw SQL data.
- Index trong DB là gì và Rails thêm index như thế nào trong migration?
Index là cấu trúc dữ liệu phụ (B-tree) giúp DB tìm kiếm nhanh theo column mà không phải scan toàn bảng. Khi nào cần index: - Foreign key columns (userid, postid) → luôn cần để JOIN nhanh. - Columns thường xuất hiện trong WHERE /…
- Làm thế nào để viết migration an toàn trên production DB lớn (zero-downtime)?
- Partial trong Rails Views là gì? Cách dùng `render` partial?
Partial là fragment ERB tái sử dụng — file tên bắt đầu bằng (underscore). Khi truyền collection (render @posts), Rails tự lặp và dùng local variable khớp tên partial (post cho post.html.erb) — không cần .each trong view.
- Flash messages trong Rails là gì? Phân biệt `flash` và `flash.now`.
flash lưu thông báo ngắn cho request tiếp theo — thường dùng sau redirectto. flash.now lưu cho request hiện tại — dùng khi render (không redirect). Flash tự xoá sau khi được đọc — không cần clean up thủ công. Trong layout, đọc bằng flash[:notice]…
- CSRF protection trong Rails hoạt động như thế nào?
CSRF (Cross-Site Request Forgery) là tấn công khiến trình duyệt nạn nhân gửi request đến server thay mặt họ. Rails bảo vệ bằng cách nhúng authenticity token (random string unique per session) vào mọi form. Controller kiểm tra token trước mọi non-GET request: Request từ…
- Concern trong Rails là gì và dùng trong Controller/Model thế nào?
Concern là module được include vào nhiều class để tái sử dụng logic. Rails cung cấp ActiveSupport::Concern để tránh boilerplate. Model Concern hoạt động tương tự — thường dùng để share scope, callback, hay helper method giữa nhiều model. Concern tốt cho logic dùng ở…
- Session và Cookie trong Rails khác nhau như thế nào?
Cookie Session --------- Lưu ở đâu Trình duyệt Server (hoặc encrypted cookie) Xem được Có (dễ đọc) Không (mã hoá hoặc server-side) Kích thước 4KB Không giới hạn (server-side) Cookies lưu plaintext hoặc signed (cookies.signed[:userid]). Session mặc định dùng CookieStore — toàn bộ session được…
- Service Object trong Rails là gì và vì sao nên dùng?
- Rails hỗ trợ những loại test nào? Phân biệt unit test, integration test và system test.
Rails tích hợp sẵn Minitest. Hầu hết project thực tế dùng RSpec thay thế. Loại test Phạm vi Tool --------- Unit (model) Test 1 model, không browser type: :model (RSpec) / ActiveSupport::TestCase Controller/Request Test action, params, response code type: :request (RSpec) Integration Test nhiều layer,…
- Active Job là gì? Tại sao cần xử lý background job trong Rails?
Active Job là interface thống nhất để tạo và enqueue background jobs — có thể chạy với nhiều backend (Sidekiq, Resque, GoodJob) mà không đổi code job. Tại sao cần: một số tác vụ không nên chạy trong HTTP request vì tốn thời gian hoặc…
- Sidekiq là gì và khác Active Job như thế nào?
Active Job là abstraction layer — định nghĩa interface chung, Rails tích hợp sẵn. Sidekiq là backend cụ thể dùng Redis để store và process job — nổi tiếng nhất cho Rails. Sidekiq dùng multi-threading (concurrency ~25 mặc định) → xử lý nhiều job song…
- Test Active Job / Sidekiq như thế nào với RSpec?
Rails cung cấp ActiveJob::TestHelper với matchers tích hợp. Dùng performenqueuedjobs để flush queue ngay trong test. Để test job perform trực tiếp, gọi describedclass.performnow(id) và assert side-effect (mail gửi, record thay đổi, v.v.).
- Action Mailer trong Rails dùng để làm gì? Cách gửi email async?
Action Mailer cho phép tạo và gửi email từ Rails, tương tự như Controller nhưng cho email. View nằm ở app/views/usermailer/welcome.html.erb. Test với ActionMailer::Base.deliveries (test mode tích hợp sẵn).
- Idempotency trong background job là gì và tại sao quan trọng?
- Asset Pipeline trong Rails là gì? Vai trò của nó là gì?
Asset Pipeline (Sprockets) là framework gom, minify và fingerprint static assets (JS, CSS, images) trước khi deploy. Vai trò chính: - Concatenation: gộp nhiều file JS/CSS thành 1 file → giảm HTTP requests. - Minification: xoá whitespace/comments → file nhỏ hơn. - Fingerprinting: thêm hash…
- Rack là gì? Rails liên quan đến Rack như thế nào?
- Helper methods trong Rails Views là gì? Phân biệt `link_to`, `form_with`.
Helper method là Ruby method available trong view/template để tạo HTML tags và link. formwith model: @post tự biết dùng POST /posts (tạo mới) hay PATCH /posts/:id (cập nhật) dựa vào @post.persisted?. Từ Rails 5.1+ formwith thay thế formfor và formtag.
- Namespace và Scope trong Rails Router khác nhau như thế nào?
namespace và scope đều nhóm route, nhưng ảnh hưởng khác nhau: namespace :admin scope :admin --------- URL prefix /admin/posts /admin/posts Controller Admin::PostsController PostsController Named helper adminpostspath postspath Dùng namespace cho admin panel (muốn tất cả đều tách biệt). Dùng scope cho API versioning khi muốn…
- Polymorphic Association trong Rails là gì? Cho ví dụ thực tế.
Polymorphic association cho phép một model belongsto nhiều model khác nhau qua cùng một association. Ví dụ: Comment có thể thuộc về Post hoặc Video. Cột commentabletype lưu tên class, commentableid lưu id. Rails tự handle việc lọc.
- Single Table Inheritance (STI) trong Active Record là gì? Khi nào dùng, khi nào không?
STI lưu nhiều subclass khác nhau vào một bảng DB dùng cột type để phân biệt. Dùng khi: các subclass có phần lớn attribute giống nhau, chỉ khác behavior. Không dùng khi: subclass có nhiều attribute riêng → bảng sẽ có nhiều cột bỏ trống…
- Transactions trong Active Record là gì? Khi nào cần dùng?
Transaction đảm bảo các thao tác DB hoặc commit hết, hoặc không commit gì — nếu bất kỳ bước nào fail, toàn bộ rollback. Transaction tự động bao quanh mỗi save / create / destroy. Cần explicit transaction khi: - Nhiều thao tác DB phụ…
- Optimistic vs Pessimistic Locking trong Rails là gì?
- Counter Cache trong Rails là gì và dùng như thế nào?
- Tại sao không nên dùng model class trong migration? Cách xử lý đúng khi cần migrate data.
Gọi model class (VD: User.updateall(...)) trong migration nguy hiểm vì model thay đổi theo thời gian — migration cũ sẽ fail khi replay (setup fresh DB) vì model không còn method/association đó nữa. Sai: Đúng — dùng anonymous model hoặc raw SQL:
- Layout trong Rails là gì? Cách chọn layout khác nhau cho từng controller?
Layout là "wrapper" HTML chứa phần chung của trang (header, footer, nav). Mặc định mọi action dùng app/views/layouts/application.html.erb. Chọn layout theo controller: Dùng render layout: false để render không có layout (API response JSON).
- Caching trong Rails — fragment cache và Russian-doll cache là gì?
Caching giảm số lần tính toán/query tốn kém bằng cách lưu kết quả HTML. Fragment cache — cache một đoạn view: Russian-doll cache — cache lồng nhau: outer cache bao inner cache. Outer chỉ expired khi inner thay đổi. Khi 1 comment thay đổi →…
- Content negotiation trong Rails — `respond_to` và `respond_with` dùng như thế nào?
Content negotiation cho phép một action phản hồi theo format khác nhau (HTML, JSON, XML) tuỳ Accept header hoặc URL extension. Request GET /posts/1 → HTML. GET /posts/1.json hoặc header Accept: application/json → JSON. respondwith (từ gem responders) ngắn gọn hơn cho CRUD chuẩn nhưng…
- Rails API mode là gì? Khác gì so với full Rails app?
- Factory Bot là gì? Khác fixture như thế nào?
Factory Bot (trước là FactoryGirl) là gem tạo test data linh hoạt — thay thế fixtures (file YAML static) bằng Ruby code. Fixture load toàn bộ vào DB trước khi test — nhanh nhưng cứng, khó hiểu quan hệ. Factory Bot tạo khi cần —…
- Mocks và Stubs trong RSpec là gì? Khi nào dùng cái nào?
Stub thay thế method thật bằng kết quả giả — kiểm soát đầu ra, không quan tâm có gọi hay không. Mock là stub + có kỳ vọng rằng method phải được gọi — test sẽ fail nếu không gọi. Khi nào dùng: - Stub:…
- DatabaseCleaner trong Rails testing dùng để làm gì? Các strategy phổ biến?
DatabaseCleaner đảm bảo mỗi test bắt đầu với DB sạch — tránh test state rò rỉ sang test khác. Ba strategy chính: Strategy Cơ chế Tốc độ Dùng khi ------------ transaction Wrap test trong transaction, rollback sau Nhanh nhất Unit/request test không cần JS truncation…
- Cron job trong Rails — Active Job scheduler vs gem whenever? Cách setup scheduled job?
- Retry và dead queue trong Sidekiq hoạt động như thế nào?
- Enum trong Active Record là gì? Cách định nghĩa và dùng trong query?
- `delete` và `destroy` trong Active Record khác nhau thế nào?
Cả hai đều xoá bản ghi, nhưng đi qua hai đường khác nhau: - destroy: nạp object lên, chạy callbacks (beforedestroy, afterdestroy, aftercommit) và xử lý association khai báo dependent: :destroy. Đây là đường "an toàn" khi có logic phụ thuộc. - delete: bắn thẳng…
- `after_save` và `after_commit` khác nhau ở thời điểm nào trong transaction?
Khác biệt nằm ở quan hệ với transaction của database: - aftersave: chạy bên trong transaction, ngay sau khi INSERT/UPDATE được gửi nhưng trước khi COMMIT. Nếu về sau transaction rollback, mọi thứ aftersave làm cũng bị huỷ theo nếu nằm trong DB — nhưng…
- Khi nào dùng `has_many :through` thay vì `has_and_belongs_to_many`?
Cả hai mô hình quan hệ nhiều-nhiều, khác nhau ở chỗ có model trung gian hay không: - hasandbelongstomany (HABTM): chỉ cần một bảng nối (vd authorsbooks), không có model cho nó. Gọn khi quan hệ thuần tuý là "nối", không có dữ liệu kèm…
- Active Storage đính kèm file vào model như thế nào?
Active Storage là framework tích hợp sẵn để đính kèm file (ảnh, PDF...) và upload lên cloud (S3, GCS, Azure) hoặc disk local. Cần chạy rails activestorage:install một lần để tạo các bảng activestorageblobs, activestorageattachments. Khai báo trên model và attach: Điểm cốt lõi: -…
- Scaffolding trong Rails là gì?
Scaffolding là generator sinh sẵn toàn bộ stack CRUD cho một resource chỉ bằng một lệnh: model + migration + controller + views + route + test. Sau lệnh này bạn có ngay: - app/models/post.rb và migration tạo bảng posts. - PostsController với 7 action…
- `save`, `save!`, `update` và `update_attribute` khác nhau thế nào?
Khác nhau ở hai trục: có chạy validation không và thất bại thì báo bằng cách nào. Method Chạy validation Khi thất bại --- --- --- save Có Trả false save! Có Ném ActiveRecord::RecordInvalid update Có Trả false update! Có Ném exception updateattribute Không Bỏ…
- `pluck`, `select` và `map` khác nhau thế nào khi chỉ cần một cột?
pluck lấy thẳng cột từ DB và trả về mảng các giá trị, không dựng object Active Record. - map tải toàn bộ cột và khởi tạo đầy đủ model cho mỗi dòng — tốn RAM nhất. - select vẫn dựng model nhưng chỉ nạp…
- `ActiveRecord::Relation` lazy nghĩa là gì? Khi nào query mới thực sự chạy DB?
Relation là một mô tả query chưa chạy. Rails chỉ gửi SQL xuống DB khi bạn thực sự cần tới dữ liệu — gọi là loading. Kích hoạt query: toa, each, first, last, find, count, sum, pluck, any?, hoặc khi render trong view. Không kích…
- Xử lý 5 triệu record thì dùng `each` hay `find_each`? Vì sao?
Dùng findeach. User.all.each nạp toàn bộ 5 triệu dòng vào RAM trước khi lặp — process rất dễ bị OOM kill. findeach chia thành từng lô (mặc định 1000 record), nạp lô nào xử lý lô đó rồi giải phóng: Lưu ý: findeach ép sắp…
- `includes`, `preload` và `eager_load` khác nhau thế nào? Khi nào dùng cái nào?
Cả ba đều nạp trước association để tránh N+1, khác ở SQL sinh ra. - preload — luôn chạy query riêng cho mỗi association (SELECT ... WHERE postid IN (...)). Không thể lọc theo cột của bảng liên kết. - eagerload — gộp thành một…
- Khi nào **không** nên dùng Active Record callback? Thay bằng gì?
Callback hợp lý khi việc cần làm gắn liền với chính bản ghi và phải đúng trong mọi ngữ cảnh: chuẩn hoá dữ liệu (beforesave { self.email = email.downcase }), sinh slug, dọn file đính kèm khi destroy. Nên tránh khi callback gây side effect…
- Low-level caching với `Rails.cache.fetch` dùng thế nào? Cần lưu ý gì về key và hết hạn?
Rails.cache.fetch đọc cache theo key; nếu chưa có (cache miss) thì chạy block, lưu kết quả rồi trả về. Key phải chứa mọi thứ ảnh hưởng tới kết quả — id, locale, phiên bản dữ liệu. Cách thông dụng là dùng chính record làm key…
- Truyền tham số cho `perform_later` cần lưu ý gì? Truyền object Active Record được không?
Được, nhưng chỉ vì Active Job không gửi object đi — nó serialize thành GlobalID (chuỗi dạng gid://app/User/42) rồi khi worker chạy mới find lại từ DB. Hệ quả cần biết: - Nếu record bị xoá trước khi job chạy, job ném ActiveJob::DeserializationError (bọc RecordNotFound).…
- Viết một Rack middleware để log thời gian xử lý request như thế nào? Chèn vào stack ở đâu?
Middleware Rack là một object có call(env) trả về mảng [status, headers, body], và giữ tham chiếu tới middleware kế tiếp (@app). Đăng ký trong config/application.rb: Vị trí quan trọng: đặt càng gần đầu stack thì càng đo được nhiều (kể cả thời gian của…
- Trên association, `size`, `count` và `length` khác nhau thế nào?
Khác ở chỗ có chạy SQL không và có nạp record vào bộ nhớ không. - count — luôn chạy SELECT COUNT(), kể cả khi association đã được nạp. Không giữ record. - length — luôn nạp toàn bộ record vào mảng rồi đếm trong…
- Model `Order` đã phình lên 900 dòng. Bạn refactor thế nào — concern, service object hay PORO?
- User bấm nút "Đặt hàng" hai lần liên tiếp, hàng chỉ còn 1 sản phẩm. Bạn thiết kế luồng thế nào để không bán quá tồn kho và không tạo trùng đơn?
- Thêm index vào bảng 50 triệu dòng trên Postgres production. Migration viết thế nào để không khoá ghi?