Repository Pattern in Rails

Gần đây mình có tìm hiểu về Ruby on Rails, trước đó mình code PHP trên framework Laravel. Những ai làm Laravel thì chắc quen với Repository Pattern. Repository là một phong cách thiết kế code thực hiện việc tách biệt giữa data access logic và business logic, nó được thực hiện bằng cách thêm vào một tầng nằm giữa Business Logic và Data Source, gọi là các Repository - nơi lưu trữ tất cả code liên quan đến việc truy cập dữ liệu.
Khi nhảy vào học Rails, mình cũng tìm hiểu ngay về vấn đề này. Bài viết hôm nay mình sẽ demo nho nhỏ về Repository trong Rails.
Bây giờ chúng ta hãy cùng xem một action create quen thuộc dưới đây nhé

1
2
3
4
5
6
7
8
def create
@user = User.new(user_params)
if @user.save
redirect_to user_path(@user), notice: 'User has been created'
else
render :new
end
end

Rất là quen thuộc phải không các bạn. Còn có thêm protecting attributes user_params nữa nhưng mình không cho vào, chắc các bạn cũng biết rồi. Mà mình thấy lúc trước có thể dùng attr_accessible mà không rõ lý do gì mà nó lại bị khai tử và bắt mình phải viết thêm method user_params nựa, hay họ sợ developer nhầm lẫn giữa attr_accessible và attr_accessor chăng, thôi kệ đi.
Bây giờ chúng ta sẽ tiến hành tách ra bằng việc sử dụng Repository pattern để trừu tượng hóa cách tương tác với cơ sở dữ liệu.
Các bạn hãy tạo lớp UserRepository trong thư mục app/repositories chịu trách nhiệm tương tác với cơ sở dữ liệu nhé.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class UserRepository
def all
User.all
end

def find(id)
User.find(id)
end

def new_entity(attrs = nil)
User.new(attrs)
end

def save(user)
user.save
end

def delete(user)
user.destroy
end
end

Bây giờ thì bạn có thể sử dụng trong controller rồi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class UsersController < ApplicationController
before_action :set_user, only: [:edit, :show]

def show
end

def create
@user = repo.new_entity(user_params)

if repo.save(@user)
redirect_to user_path(@user), notice: 'User has been created'
else
render :new
end
end

def edit
end

private

def set_user
@user = repo.find(params[:id])
end

def user_params
params.require(:user).permit(:first_name, :last_name, :password)
end

def repo
@repo ||= UserRepository.new
end
end

Việc sử dụng Repository đem lại một số lợi ích sau:

  • Chúng ta không phải tương tác trực tiếp mới model trong controller nữa.
  • Cấu trúc code dễ nhìn và dễ hiểu
  • Code dễ đọc hơn, chúng ta chỉ cần focus vào data access logic nên khi có thay đổi gì thì cũng sẽ dễ dàng hơn trong việc maintain code.

Để triễn khai đúng Repository Pattern thì bạn cần phải tạo ra BaseRepository và định nghĩa các method thường được sử dụng trong lớp này, ứng với mỗi model thì ta sẽ tạo ModelNameRepository kế thừa từ BaseRepository. ModelNameRepository chỉ cần định nghĩa thêm những phương thức của riêng nó, còn các phương thức cơ bản như find, all.. đã có trong Base rồi. Việc làm này nhằm tăng tính tái sử dụng và giảm thiểu trùng lặp code.

Trên đây là những chia sẽ của mình về cách sử dụng Repository trong Rails, hi vọng nó sẽ hữu ích cho các bạn.