Different Ways to Set Attributes in ActiveRecord (Rails 4)
Bài đăng này đã không được cập nhật trong 8 năm
Khi bắt đầu học Ruby on Rails, mình thấy có rất nhiều cách để thay đổi các attributes của một object và không biết khi nào nên dùng cách nào. Tuy nhiên sau quá trình tìm hiểu, mình đã tìm được một bài viết rất hay, có tổng hợp đầy đủ các cách để thay đổi thuộc tính trong Rails và sự khác nhau giữa chúng, bài viết đã giúp mình rất nhiều. Sau đây mình xin giới thiệu nội dung của bài viết đó, hi vọng nó sẽ giúp các bạn sử dụng Active Record hiệu quả hơn.
Nguồn: http://www.davidverhasselt.com/set-attributes-in-activerecord/
Trong nội dung bài viết chúng ta sẽ xét một đối tượng user
của class User
với các thuộc tính là :name
, :age
I. Bảng so sánh tổng quát
Method | Uses Default Accessor | Saved to Database | Validations | Callbacks | Update updated_at column | Readonly check |
---|---|---|---|---|---|---|
attribute= assign_attribute |
yes | no | n/a | n/a | n/a | n/a |
write_attribute |
no | no | n/a | n/a | n/a | n/a |
update_attribute |
yes | yes | no | yes | yes | yes |
attributes= |
yes | no | n/a | n/a | n/a | n/a |
update update_attributes |
yes | yes | yes | yes | yes | yes |
update_column |
no | yes | no | no | no | yes |
update_columns |
no | yes | no | no | no | yes |
User::update |
yes | yes | yes | yes | yes | yes |
User::update_all |
no | yes | no | no | no | no |
user.increment(:age, 10) user.decrement(:age, 10) |
no | n/a | n/a | n/a | n/a | |
user.increment!(:age, 10) user.decrement!(:age, 10) |
yes | no | yes | yes | yes |
- Touches updated_at: Các phương thức khi thực hiện có cập nhật giá trị mới cho trường created_at hay không.
- Readonly check: Với những phương thức có check readonly, chúng sẽ raise exception nếu có bất kì cột nào được đánh dấu là readonly
II. Chi tiết các phương thức
1. user.name = "Rob"
Đây có lẽ là phương thức phổ biến và dễ sử dụng nhất. Với phương thức này, thuộc tính name
sẽ được thay đổi và chưa được lưu vào database cho tới khi lệnh save
được gọi. Với các thay đổi chưa được lưu vào database bạn có thể kiểm tra bằng câu lệnh user.changed?
. Bạn cũng có thể reload các thay đổi tạm thời này bằng lệnh user.reload
2. user.write_attribute(:name, "Rob")
Phương thức này được gọi bởi accessor mặc định phía trên. Ngoài ra nó còn có cách viết tương đương là user[:name] = "Rob"
. Các thay đổi của phương thức này không được lưu vào database.
Ví dụ:
def name=(new_name)
write_attribute(:name, new_name.upcase)
# This is equivalent:
# self[:name] = new_name.upcase
end
3. user.update(name: "Rob")
và user.update_attributes(name: "Rob")
Trên Rails 4 ta có phương thức user.update
và phiên bản trước đó của nó trên Rails 3 là user.update_attributes
.
Đây là phương thức rất phổ biến, được dùng để thay đổi một hoặc nhiều thuộc tính của đối tượng và lưu các thay đổi này vào database.
Ví dụ khi update nhiều thuộc tính
user.update(name: "sadfdasfa", age: 22)
4. user.update_attribute(:name, "Rob")
Phương thức này được dùng để thay đổi một thuộc tính của đổi tượng và lưu các thay đổi này vào database. Khi sử dụng phương thức này, các validate sẽ không được gọi, tương tự như khi bạn sử dụng hàm save(validate: false)
Do các validate không được gọi nên dẫn tới việc dữ liệu sai có thể được lưu vào database. Do đó user.update
và user.update_attributes
thường được sử dụng thay vì user.update_attribute
5. user.attribute=
và user.assign_attribute
Hai phương thức này gán giá trị cho một hoặc nhiều thuộc tính của đối tượng tuy nhiên chưa lưa các thay đổi này vào database. Ví dụ:
user.attributes = {name: "Rob", age: 12}
user.assign_attributes {name: "Rob", age: 12}
Hai cách dùng này là tương đương nhau.
6. user.update_columns(name: "Rob")
Phương thức này sẽ gọi trực tiếp câu truy vấn SQL UPDATE để thay đổi một hoặc nhiều thuộc tính. Do câu truy vấn SQL được gọi trực tiếp mà không gọi qua hàm save
nên các validates và callbacks sẽ bị bỏ qua. Ngoài ra nó cũng kiểm tra nếu có bất kì columns nào được đánh dấu readonly
thì sẽ raise ra lỗi.
Do tất cả callbacks và validates sẽ không được gọi nên phương thức này ít được dùng trong chương trình hơn so với update_attributes
nó sẽ hữu ích khi bạn muốn khởi tạo nhanh các giá trị để test các chức năng mà không liên quan đến validates và callbacks.
7. user.update_column(:name, "Rob")
Tương tự như user.update_columns(name: "Rob")
nhưng phương thức này chỉ dùng để thay đổi một thuộc tính
8. User.update(1, name: "Rob")
Lại một phương thức update
khác tuy nhiên đây là một class method không phải instance method như hàm update
được giới thiệu ở mục 3.
Với phương thức này bạn có thể dùng để thay đổi nhiều thuộc tính của nhiều đối tượng cùng lúc. Khi muốn thay đổi nhiều đối tượng cùng lúc, ta có hai cách viết khác nhau
Cách 1:
User.update(
[1,2,3],
[
{name: "Rob"},
{name: "David", age: 12},
{age: 15, location: "London"},
]
)
Cách 2:
User.update(1 => {name: "Rob"}, 2 => {name: "David", age: 12}, 3 => {age: 15, location: "London"})
9. User.update_all(name: "Rob")
Đây cũng là một class method khác và phương thức này cũng chạy trực tiếp câu truy vấn SQL UPDATE nên nó cũng lưu các thay đổi và database nhưng bỏ qua validates và callbacks.
Ví dụ đổi tên tất cả các user tên "Robbie" thành "Rob"
User.where(name: "Robbie").update_all(name: "Rob")
10. user.increment(:age, 10)
và user.decrement(:age, 10)
Đây là hai hàm được dùng để tăng hoặc giảm giá trị của một thuộc tính nào đó đi một số. Những giá trị thay đổi này sẽ không được lưu vào database. Tuy nhiên sau khi dùng hàm này, bạn kiểm tra bằng lệnh user.changed?
sẽ trả về kết quả false.
Nếu giá trị ban đầu là nil thì kết quả sẽ là 0.
11. user.increment!(:age, 10)
và user.decrement!(:age, 10)
Khác với hai hàm trên, hai hàm này sẽ lưu các thay đổi vào database sử dụng hàm update_attribute
. Do đó nó cũng gọi các callback nhưng không check validate tương tự như khi bạn sử dụng update_attribute
All rights reserved