Ví dụ mình có một model User và 1 user có nhiều Reviews (User has_many Reviews). User có thuộc tính bắt buộc là user_name, và Review có thuộc tính bắt buộc là title.

1. Đối với User khởi tạo mới (chưa được lưu vào DB).

Đúng cho cả các quan hệ belongs_to, has_many, has_one, has_many_and_belongs_to

Dùng toán tử << (giống với push array) sẽ nối thêm vào mảng những phần tử cần thêm.

Đoạn code sau sẽ trả về một collection:

u = User.new
bad_review = Review.new
good_review = Review.new(:title => "An awesome review")
u.reviews << [good_review, bad_review, bad_review]

# => [
    #<Review id: nil, user_id: nil, title: "An awesome review", created_at: nil, updated_at: nil>, 
    #<Review id: nil, user_id: nil, title: nil, created_at: nil, updated_at: nil>, 
    #<Review id: nil, user_id: nil, title: nil, created_at: nil, updated_at: nil>
 #]

Khi tiến hành lưu User u phía trên sẽ không lưu được vì User u và bad_review chưa có thuộc tính bắt buộc để lưu vào DB (user_name và title) (phải cả 2 cùng hợp lệ)

u.save
#    (0.1ms)  BEGIN
#    (0.3ms)  SELECT 1 FROM `users` WHERE `users`.`username` = BINARY '' LIMIT 1
#    (0.1ms)  ROLLBACK

 

Muốn lưu được User u trên cần phải validate các object đúng định dạng:

u.username = "gerry"
bad_review.title = "A super awesome title"
u.save
#      (0.2ms)  BEGIN
#      (0.6ms)  SELECT 1 FROM `users` WHERE `users`.`username` = BINARY 'gerry' LIMIT 1
#       sql insert for user
#      (0.4ms)  INSERT INTO `reviews` (`created_at`, `title`, `updated_at`, `user_id`) VALUES ('2011-08-04 09:28:36', 'An awesome review', '2011-08-04 09:28:36', 8)
#      (0.4ms)  INSERT INTO `reviews` (`created_at`, `title`, `updated_at`, `user_id`) VALUES ('2011-08-04 09:28:36', 'A super awesome title', '2011-08-04 09:28:36', 8)
#      (61.2ms)  COMMIT

 

Chú ý: 

- Như ta thấy các câu lệnh query phía trên, chỉ có 2 review được insert vào DB là good_review và bad_review, dù ta có push 2 lần object bad_review vào User u đi chăng nữa thì cũng chỉ insert có một bad_review.

- Vì u vẫn nằm trong bộ nhớ và đang có 3 reviews được push vào ban đầu là good_review, bad_review, bad_review nên khi ta gọi u.reviews vẫn ra 3 reviews:

 

u.reviews
# => [
   #<Review id: 8, user_id: 8, title: "An awesome review", created_at: "2011-08-04 09:28:36", updated_at: "2011-08-04 09:28:36">, 
   #<Review id: 9, user_id: 8, title: "A super awesome title", created_at: "2011-08-04 09:28:36", updated_at: "2011-08-04 09:28:36">, 
   #<Review id: 9, user_id: 8, title: "A super awesome title", created_at: "2011-08-04 09:28:36", updated_at: "2011-08-04 09:28:36">
 #]

 

- Nhưng nếu ta load lại User u từ DB thì chỉ có 2 reviews mà thôi:

u = User.first
u.reviews
# => Review Load (0.3ms)  SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 8
# => [
   #<Review id: 8, user_id: 8, title: "An awesome review", created_at: "2011-08-04 09:28:36", updated_at: "2011-08-04 09:28:36">, 
   #<Review id: 9, user_id: 8, title: "A super awesome title", created_at: "2011-08-04 09:28:36", updated_at: "2011-08-04 09:28:36">
 #]

 

2. Đối User được lấy ra từ DB

- Đối với quan hệ has_one, has_many, has_many_and_belongs_to

Đối với User được lấy ra từ DB rồi dùng toán tử << hoặc push thì lúc này các object được truyền vào sẽ trực tiếp được lưu vào DB luôn (nếu không thiết đặt autosave: true trong model cha) mà không cần gọi hàm save nữa, tất nhiên là các object truyền vào vẫn phải validate đúng:

u = User.find_by_username("claire") // get from DB
u.reviews << good_review
#  (0.1ms)  BEGIN
#  (0.2ms)  INSERT INTO `reviews` (`created_at`, `title`, `updated_at`, `user_id`) VALUES ('2011-08-04 09:49:46', 'An awesome review', '2011-08-04 09:49:46', 3)
#  (158.3ms)  COMMIT
# => returns the collection
 
u.reviews << bad_review
#  (0.1ms)  BEGIN
#  (0.0ms)  COMMIT
# => false  

Như đoạn code trên good_review sẽ được lưu vào DB luôn khi dùng toán tử << hoặc push, còn bad_review sẽ không được lưu vì chưa được truyền title vào.

- Đối với quan hệ belongs_to

Nếu review được lấy ra từ DB thì không thể sử dụng push hoy << được vì review.user không phải là array. Khi gán giá trị khác cho review.user thì giá trị đó cũng không được lưu vào user.

 

a. Khi không thiết đặt autosave trong model.

Chỉ tự động lưu với các association là new_record? Nếu không phải thì sẽ không tự động lưu.

 

b. Khi thiết đặt autosave: true trong model.

class User
   has_many :reviews, autosave: true
   ....
end

class Review
   belongs_to :user
   ....
end

 Tự động lưu với các association dù là new_record? hay không.

c. Khi thiết đặt autosave: false trong model

 Sẽ không tự động lưu dù association có là new_record? hay không.