2012-11-05 24 views
6

Tôi đang làm việc trên ứng dụng Rails 3.2.8 sử dụng API REST trong nhà để chèn dữ liệu mới. Logic chèn là chung cho mọi điểm cuối và kết quả khá đơn giản trong một cuộc gọi đến Model.save.Ghi đè đường ray Lưu để thực hiện cập nhật có chọn lọc

Đối với một trong các loại mô hình, trước tiên tôi muốn kiểm tra xem có tồn tại một bản ghi đã tồn tại chưa và nếu có, hãy cập nhật thay vì chèn. Nếu mã cho phép tôi tương tác ở cấp điều khiển, điều này sẽ dễ dàng thông qua việc sử dụng find_or_create_by, tuy nhiên (tôi nghĩ) tùy chọn duy nhất của tôi là ghi đè phương thức lưu trong Mô hình hoặc sử dụng gọi lại before_save.

Tôi đang cố gắng tìm ra cách để thực hiện công việc này, vì mọi cuộc gọi để lưu hoặc update_attributes bên trong Mô hình đơn giản dẫn đến vòng lặp vô hạn (vì lý do hiển nhiên). Có cách nào để sử dụng before_save hoặc ghi đè lưu theo cách mà trước tiên tôi có thể kiểm tra xem bản ghi có tồn tại với thuộc tính x và y không và nếu có, hãy truy lục bản ghi đó và thực hiện cập nhật, nếu không hãy tiếp tục với tiêu chuẩn ActiveRecord tiết kiệm?

Đây là mã của tôi vì nó hiện đang đứng bên trong mô hình hoạt động, mà không làm việc do các vấn đề vòng lặp vô hạn:

def save 
    a = UserActivity.find_or_initialize_by_user_id_and_activity_id(user_id: user_id,  activity_id: activity_id) 
    a.update_attributes start_at: start_at, end_at: end_at..... 
end 
+0

tôi cảm thấy như chỉnh sửa 'save' có thể mở toàn bộ các sâu của các vấn đề nhạy cảm với cơ sở dữ liệu. Bạn có xem xét đơn giản bằng cách sử dụng câu lệnh 'if - else' kết hợp với' update_attributes' và 'save' không? –

Trả lời

7

Bạn đang cần find_or_create_by_* phương pháp.

Để tránh các vòng lặp, bạn không nên đặt này trong save phương pháp, nhưng thuộc một trong hai nơi này:

Lựa chọn 1: Bộ điều khiển mức

Trong điều khiển của bạn, nơi bạn instanciate UserActivity trường hợp này, bạn thay vì viết:

a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id, activity_id: activity_id) 
a.update_attributes start_at: start_at, end_at: end_at..... 

Lựa chọn 2: phương pháp lớp

Nếu bạn tìm cho mình một dding mã ở trên để vài contrllers, một cách tốt hơn sẽ được xác định một phương pháp học mới trong UserActivity:

class UserActivity 
    def self.create_or_update_from_attrs(user_id, activity_id, start_at, end_at...) 
    a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id,  activity_id: activity_id) 
    a.update_attributes start_at: start_at, end_at: end_at..... 
    end 
end 

Và trong bộ điều khiển, rõ ràng:

UserActivity.create_or_update_from_attrs(...) 

Override tiết kiệm

Trong số Tất nhiên, bạn cũng có thể ghi đè lên phương thức save nhưng điều này có chức năng sao chép Rails (find_or_create_by...) và vi phạm DRY bạn có thể tự bắn mình chân của bạn một thời gian sau khi cuộc xung đột này với một số tình huống khác mà bạn gặp phải, vì vậy tôi không khuyến khích việc sử dụng này:

EDIT: cập nhật để tránh vòng lặp vô hạn

class UserActivity 
    def save 
    # If this is new record, check for existing and update that instead: 
    if new_record? && a = UserActivity.where(user_id: user_id, activity_id: activity_id).first 
     a.update_attributes start_at: start_at, end_at: end_at ... 
     return true # just to comply with Rails conventions   
    else 
     # just call super to save this record 
     super 
    end 
    end 
end 
+0

Cảm ơn Laas. Vấn đề là lớp API là chung chung và chỉ đơn giản là các cuộc gọi lưu trên bất kỳ mô hình nào mà nó diễn giải như đang được tham gia (dựa trên cuộc gọi URI). Vì vậy, tôi không có móc ở lớp điều khiển, mà tôi đồng ý là đúng nơi để đặt logic này.Tại thời điểm tôi tham gia, phương thức lưu đã được gọi trên mô hình. Tùy chọn của bạn để ghi đè lưu vẫn dẫn đến một vòng lặp vô hạn khi update_attributes kết quả trong lưu được gọi lại trên Mô hình. – JaySquat

+0

Tôi đã cập nhật mã của mình - lần lưu thứ hai sẽ gọi là 'super' vì bản ghi không phải là 'new_record?' Nữa. – Laas

+0

Điều này làm việc hoàn hảo, cảm ơn bạn! Tôi sẽ bầu bạn, nhưng tôi chưa có đủ đại diện. – JaySquat

Các vấn đề liên quan