2016-04-18 14 views
5

Tôi có trường hợp sử dụng nơi tôi muốn sử dụng phương thức ActiveRecord :: Relation update_all và chỉ định một số trường cần đặt. Tôi sử dụng update_all vì rất nhiều mục có thể được cập nhật và tôi không muốn tải tất cả chúng và cập nhật từng cái một.Rails ActiveRecord - update_all: cách cập nhật nhiều trường cùng lúc với kiểu đối số hỗn hợp

Một số người trong số họ cần một câu lệnh SQL SET trực tiếp, ví dụ vì tôi đặt một cột theo giá trị của một cột khác.

Có một cú pháp đơn giản với update_all để làm điều này có thể đọc được, dọc theo dòng này =>

MyModel.where(state: :foo).update_all([ 
    'timespent = timespent + 500', # Can't be anything else than a SQL statement 
    state: :bar, # Regular Rails SQL interpolation 
    updated_at: DateTime.current 
]) 

Lưu ý rằng cú pháp trên không hiệu quả bởi vì nó sẽ cố gắng tìm kiếm và thay thế các giá trị placeholders , do đó, state: :barupdated_at: DateTime.current bị bỏ qua. Một giải pháp một phần cho việc này là chuyển đổi mọi thứ thành một chuỗi câu lệnh SQL như dưới đây, nhưng tôi không thích điều này quá nhiều vì tôi cần tìm ra các câu lệnh SQL, và nó hơi phức tạp khi viết mã với Rails;):

MyModel.where(state: :foo).update_all([ 
    "timespent = timespent + 500", # Can't be anything else than a SQL statement 
    "state = 'bar'", 
    "updated_at = NOW()" # Needed to translate from Rails to PGSQL 
].join(', ')) 

Bất kỳ ai có giải pháp thanh lịch không?

Cảm ơn!

+0

Nếu bạn muốn có một ứng dụng mạnh mẽ và tối ưu hóa, bạn sẽ cần phải thực hiện truy vấn SQL theo cách thủ công một số lần. Bạn nên học và cải thiện các kỹ năng SQL của mình bằng cách thực hiện sql UPDATE thông thường hơn là cố gắng sử dụng Rails để thực hiện các truy vấn SQL phức tạp. – MrYoshiji

Trả lời

5

update_all lấy một chuỗi, mảng hoặc băm (nhưng bạn không thể kết hợp và khớp). Trong trường hợp của một mảng, nó trông đợi các điều kiện của ActiveRecord Array. Vì vậy, bạn sẽ có thể làm một cái gì đó như thế này:

MyModel.where(state: :foo).update_all([ 
    'timespent = timespent + 500, state = ?, updated_at: ?', 
    'bar', 
    DateTime.current 
]) 
+1

Lưu ý, phải là 'updated_at ='. – tadman

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