Rails: Cập nhật thuộc tính mô hình mà không cần gọi lại


76

Tôi có Mô hình người dùng có thuộc tính: credit. Tôi muốn một nút đơn giản sẽ thêm 5 vào tín dụng của người dùng, thông qua một lộ trình có tên "thêm" để / người dùng / 3 / add sẽ thêm 5 vào tín dụng của user id = 3.

def add
    @user = User.find(params[:id])
    @user.credits += 5
    redirect_to root_path
end

Đó là phần có liên quan của bộ điều khiển của tôi. Vấn đề là, tôi không muốn gọi @ user.save vì tôi có lệnh gọi lại before_save mã hóa lại mật khẩu của người dùng dựa trên thời gian UTC hiện tại. Tôi chỉ muốn đơn giản là thêm 5 vào thuộc tính và tránh gọi lại, tôi chưa bao giờ nghĩ rằng một việc đơn giản lại có thể khó đến vậy.

BIÊN TẬP:

Tôi đã thay đổi lệnh gọi lại thành: before_create, đây là mã bộ điều khiển mới của tôi (phần có liên quan):

  def add
    @user = User.find(params[:id])
    @user.add_credits(5)
    @user.save
    flash[:success] = "Credits added!"
    redirect_to root_path
  end

và đây là mã của tôi trong mô hình:

 def add_credits(num)
    self.credits = num
 end

CHỈNH SỬA 2:

Được rồi, đó là sự cố xác thực khiến các thay đổi trong "EDIT" không hoạt động, nhưng tôi vẫn muốn có câu trả lời cho câu hỏi ban đầu về việc cập nhật mà không có lệnh gọi lại!


Tôi đã cung cấp một liên kết với danh sách các phương pháp không kích hoạt lệnh gọi lại và cả Finbarr và tôi đều đề xuất sử dụng lệnh gọi lại có điều kiện - bạn đang tìm kiếm giải pháp bổ sung nào?
Dave Newton

Câu trả lời:



15

Như một câu trả lời chung, trong Rails 4, đây là một cách đơn giản để cập nhật các thuộc tính mà không cần kích hoạt các lệnh gọi lại:

@user.update_column :credits, 5

Nếu bạn cần cập nhật nhiều thuộc tính mà không kích hoạt lệnh gọi lại:

@user.update_columns credits: 5, bankrupt: false  

Có các tùy chọn khác ở đây trong Hướng dẫn đường ray nếu bạn thích, nhưng tôi thấy cách này là dễ nhất.


4
tín dụng user.update_column: 5 không hoạt động. Nó phải là user.update_column 'credit', 5
Richard H Fung,

Tôi đang sử dụng Rails 4.2 và điều này chắc chắn phù hợp với tôi. Dòng này tạo ra truy vấn sau:UPDATE "users" SET "credits" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["credits", 5], ["updated_at", "2017-04-01 21:34:52.746626"], ["id", 1]]
Matt,

1
Khi sử dụng update_column, bạn không thể chuyển nó một Đối tượng như thế nào credits: 5. Bạn phải chuyển hai tham số, tham số đầu tiên là tên cột và tham số thứ hai là giá trị để cập nhật nó. Vì vậy, bạn có thể làm update_column :credits, 5, điều này thường được ưu tiên hơn là sử dụng Chuỗi cho tên cột.
Joshua Pinter

8

Để cập nhật nhiều thuộc tính mà không cần gọi lại, bạn có thể sử dụng update_all trong mô hình của mình như sau:

self.class.update_all({name: value, name: value}, self.class.primary_key => id)

Nếu bạn thực sự muốn, bạn thậm chí có thể thử ngay cả một phương thức update_columns và trộn nó vào lớp cơ sở bản ghi đang hoạt động của bạn.

Để cập nhật một thuộc tính, bạn có thể sử dụng update_column. Ngoài ra, có một số phương pháp cụ thể có thể tìm thấy trong hướng dẫn đường ray http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks


6

Đối với mongoid, tôi đã kết thúc sử dụng http://mongoid.org/en/mongoid/docs/persistence.html Cụ thể, bạn có thể sử dụng:

person.set(name:"Robert Pulson")

và sẽ không có cuộc gọi lại nào. Thật tuyệt.


person.set (: name, "Robert Pulson")
Jude Calimbas

2
@JudeCalimbas không, không phải đâu, ArgumentError: sai số đối số (cho 2, dự kiến ​​là 1)
rept

3

Tôi nghĩ bạn nên sử dụng phương thức update_counters trong trường hợp này. Sử dụng nó như thế này trong hành động điều khiển của bạn:

def add
  User.update_counters params[:id], :credits => 5
  redirect_to root_path
end

2

Bạn có thể sử dụng update_all để tránh kích hoạt các cuộc gọi lại.

def add
 @user = User.find(params[:id])
 User.where(:id=>@user.id).update_all(:credits => @user.credits+5)
 redirect_to root_path
end

Tôi muốn đặt logic này vào mô hình, nhưng điều này sẽ hoạt động để giải quyết vấn đề ban đầu của bạn như đã nêu trong bộ điều khiển.



1

Có thể hook before_save khác của bạn nên kiểm tra xem mật khẩu của người dùng đã thực sự thay đổi chưa trước khi mã hóa lại.


1

Bạn có một số lựa chọn, bao gồm thay đổi đó gọi lại bạn sử dụng, ví dụ như, after_create.

Bạn có thể cập nhật các cột mà không kích hoạt lệnh gọi lại, hãy xem Bỏ qua lệnh gọi lại trong hướng dẫn AR. Ví dụ: update_columnkhông kích hoạt gọi lại. Liên kết trước liệt kê các chức năng không kích hoạt.

Bạn cũng có thể sử dụng bất kỳ biểu mẫu Gọi lại có Điều kiện nào (hoặc thậm chí là một trình quan sát) khi mật khẩu được thay đổi. Xem ActiveModel :: bẩn , ví dụ @user.password_changed?.


Được rồi, tôi đã thay đổi nó thành "after_create" nhưng nó vẫn không hoạt động! Xem chỉnh sửa của tôi cho mã mới của tôi, tôi không thể nhận được tín dụng để thay đổi.
Sam Stern

@hatboysam Chà, nó làm điều gì đó khác - trước khi bạn thêm, bây giờ bạn đang thiết lập. Sử dụng save!để xem có ngoại lệ hay không (và / hoặc kiểm tra nhật ký và / hoặc loại bỏ bộ giảm thanh dấu lùi).
Dave Newton

0

Bạn có thể cập nhật một cột làm việc này

User.where (name: 'lily') .update_all (age: '10')

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.