2011-12-28 31 views
52

Tôi có Mô hình người dùng có thuộc tính: tín dụng. Tôi muốn có một nút đơn giản mà sẽ bổ sung thêm từ 5 đến khoản tín dụng của người dùng, thông qua một con đường được gọi là "thêm" để/người dùng/3/thêm sẽ thêm 5 đến các khoản tín dụng của người sử dụng id = 3.Đường ray: Cập nhật thuộc tính mô hình mà không cần gọi lại số gọi lại

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

Đó là phần 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ó một callback 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 thêm 5 vào thuộc tính và tránh gọi lại, tôi chưa bao giờ nghĩ một thứ đơn giản như thế có thể quá khó.

EDIT:

Tôi đã thay đổi callback để: before_create, đây là mã điều khiển mới của tôi (phần 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:

Ok đó là sự cố xác thực mà thực hiện những thay đổi trong "EDIT" không hoạt động, nhưng tôi vẫn yêu một câu trả lời cho câu hỏi ban đầu của việc cập nhật mà không gọi lại!

+0

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

Trả lời

103

Rails 3.1 giới thiệu update_column, mà là giống như update_attribute, nhưng không kích hoạt xác thực hoặc callbacks:

http://apidock.com/rails/ActiveRecord/Persistence/update_column

+0

Tôi rất thích sử dụng nhưng tôi không thể nâng cấp lên Rails 3.1 một cách rõ ràng, hoặc ít nhất là tôi không biết làm thế nào. –

+1

Bạn đang chạy phiên bản Rails nào vào lúc này? – cvshepherd

1

Có thể trình cắm trước khác của bạn sẽ 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ố tùy chọn, bao gồm cả việc thay đổi gọi lại bạn sử dụng, ví dụ: after_create.

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

Bạn cũng có thể sử dụng bất kỳ hình thức nào trong số Conditional Callback (hoặc thậm chí là người quan sát) khi mật khẩu được thay đổi. Xem ActiveModel::Dirty, ví dụ: @user.password_changed?.

+0

Ok Tôi đã đổi thành "after_create" nhưng 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. –

+0

@hatboysam Vâng, nó có điều gì đó khác biệt - 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ệ nào không (và/hoặc kiểm tra nhật ký và/hoặc loại bỏ bộ mã giảm tốc). –

2

Bạn sẽ có thể sử dụng update_all để tránh kích hoạt 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ư được xác định trong bộ điều khiển.

2

Tôi nghĩ bạn nên sử dụng phương pháp 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 
+0

update_counters/increment_counter cũng hoạt động với 2.x tốt đẹp! – rogerdpack

5

Để cập nhật nhiều thuộc tính mà không cần callbacks 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ự ly muốn bạn thậm chí có thể thử ngay cả 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òn có một số phương pháp cụ thể mà có thể được tìm thấy trong đường ray dẫn http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

+1

cuối cùng là một câu trả lời mà làm việc với đường ray 2.x, cảm ơn bạn! – rogerdpack

2

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

person.set(name:"Robert Pulson") 

và không có cuộc gọi lại nào được phát hành. Thật tuyệt.

+0

person.set (: name, "Robert Pulson") –

+1

@JudeCalimbas no no, ArgumentError: sai số đối số (cho 2, dự kiến ​​1) – rept

1

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 callbacks kích hoạt:

@user.update_column credits:5 

Nếu bạn cần cập nhật nhiều thuộc tính mà không gây nên callbacks:

@user.update_columns credits: 5, bankrupt: false 

Có là các tùy chọn khác here in the Rails Guides nếu bạn thích, nhưng tôi thấy cách này là dễ nhất.

+1

user.update_column credit: 5 không hoạt động. Nó phải là user.update_column 'credits', 5 –

+0

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 truy vấn sau: "UPDATE" người dùng "SET" tín dụng "= $ 1," updated_at "= $ 2 WHERE" người dùng "." Id "= $ 3 [[" credits ", 5], [" updated_at "," 2017 -04-01 21: 34: 52.746626 "], [" id ", 1]]' – Matt

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