Rails: update_attribution vs update_attribut


255
Object.update_attribute(:only_one_field, "Some Value")
Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

Cả hai sẽ cập nhật một đối tượng mà không cần phải thông báo rõ ràng cho AR để cập nhật.

API Rails cho biết:

cho update_attribution

Cập nhật một thuộc tính duy nhất và lưu bản ghi mà không cần thông qua quy trình xác nhận thông thường. Điều này đặc biệt hữu ích cho các cờ boolean trên các bản ghi hiện có. Phương thức update_attribution thông thường trong Base được thay thế bằng phương thức này khi mô đun xác nhận được trộn lẫn, theo mặc định.

cho update_attribut

Cập nhật tất cả các thuộc tính từ Hash truyền vào và lưu bản ghi. Nếu đối tượng không hợp lệ, việc lưu sẽ thất bại và sai sẽ được trả về.

Vì vậy, nếu tôi không muốn xác thực đối tượng, tôi nên sử dụng update_attribution. Điều gì sẽ xảy ra nếu tôi có bản cập nhật này trên before_save, nó sẽ stackoverflow?

Câu hỏi của tôi là update_attribution cũng bỏ qua trước khi lưu hoặc chỉ xác nhận.

Ngoài ra, cú pháp chính xác để chuyển một hàm băm đến update_attribut là gì ... hãy xem ví dụ của tôi ở trên cùng.


Tại sao bạn muốn đặt một update_attributetuyên bố trong một before_savecuộc gọi lại? Tôi không thể nghĩ ra một lý do tốt cho việc này.
Daniel Pietzsch

1
Tôi có các đối tượng cần được cập nhật dựa trên số tiền của đối tượng được cập nhật. Cách tốt hơn là gì?
thenengah

Tôi có đúng không, rằng các đối tượng bạn cần cập nhật là thuộc tính của đối tượng bạn đang lưu? Nếu có, thì bạn chỉ có thể đặt chúng và chúng sẽ được cập nhật cùng với đối tượng được lưu bằng mọi cách (vì chúng được đặt trong một before_savecuộc gọi lại). Fe thay vì update_attribute(:discount, 0.1) if amount > 100bạn có thể làm discount = 0.1 if amount > 100. update_attributecác cuộc gọi savetrên đối tượng, không cần thiết trong trường hợp này, vì câu lệnh nằm trong một before_savecuộc gọi lại và dù sao cũng sẽ được lưu lại. Tôi hy vọng điều đó đúng.
Daniel Pietzsch

Có và không. Tuy nhiên, trạng thái của các đối tượng mà bạn đang đề cập phụ thuộc vào các điều kiện khác không thể xử lý trước khi lưu.
thenengah

3
như một lưu ý, các phương thức này bỏ qua xác thực nhưng vẫn sẽ thực hiện các cuộc gọi lại, như after_save ...
rogerdpack

Câu trả lời:


328

Vui lòng tham khảo update_attribute. Khi nhấp vào nguồn hiển thị, bạn sẽ nhận được mã sau

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2614
2614:       def update_attribute(name, value)
2615:         send(name.to_s + '=', value)
2616:         save(false)
2617:       end

và bây giờ tham khảo update_attributesvà xem mã của nó bạn nhận được

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2621
2621:       def update_attributes(attributes)
2622:         self.attributes = attributes
2623:         save
2624:       end

sự khác biệt giữa hai là update_attributesử dụng save(false)trong khi update_attributessử dụng savehoặc bạn có thể nói save(true).

Xin lỗi vì mô tả dài nhưng những gì tôi muốn nói là quan trọng. save(perform_validation = true), nếu perform_validationsai, nó bỏ qua (bỏ qua sẽ là từ thích hợp) tất cả các xác nhận liên quan đếnsave .

Đối với câu hỏi thứ hai

Ngoài ra, cú pháp chính xác để chuyển một hàm băm đến update_attribut là gì ... hãy xem ví dụ của tôi ở trên cùng.

Ví dụ của bạn là chính xác.

Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

hoặc là

Object.update_attributes :field1 => "value", :field2 => "value2", :field3 => "value3"

hoặc nếu bạn nhận được tất cả dữ liệu & tên trường trong hàm băm, hãy params[:user]sử dụng ở đây

Object.update_attributes(params[:user])

7
Tuyên bố của bạn về cuộc gọi lại là không chính xác, ít nhất là trong Rails 3. Nó nói rất rõ ràng trong các ý kiến ​​trong nguồn rằng "Gọi lại được gọi".
Batkins

Tôi thứ hai những gì @Batkins nói
Raf

3
@Batkins vẫn còn hiệu lực không được chạy - đó là phần quan trọng nhất :)
Tigraine

1
Các liên kết ở trên không còn chính xác ít nhất là trong Rails 5.1 . Các phương thức này đã được chuyển sang ActiveRecord :: Persistence. Bạn có thể tìm thấy thông tin cập nhật tại đây: thuộc tính update và tại đây update_attribut Lưu ý: update_attributeshiện là bí danh choupdate
tgf

74

Mẹo: update_attribute đang bị phản đối trong Rails 4 thông qua Cam kết a7f4b0a1 . Nó loại bỏ có update_attributelợi cho update_column.


45
Điều này không còn đúng nữa; phương pháp đã được thêm lại. Xem github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis

20
update_attributebỏ qua xác thực, nhưng tôn trọng các cuộc gọi lại, update_columnsẽ bỏ qua cả xác thực và gọi lại và không cập nhật :updated_at, updatelà chức năng bình thường sẽ tôn trọng cả cuộc gọi lại và xác thực
Mohammad AbuShady

2
họ sẽ làm cho tâm trí của họ đã. reset_column, update_column cũng không dùng nữa.
ahnbizcad

2
update_columnkhông được tán thành, nhưng update_columns(name: value)được ưa chuộng. reset_columnđã bị loại bỏ.
onebree 7/07/2015

15

update_attribution

Phương thức này cập nhật thuộc tính duy nhất của đối tượng mà không cần gọi xác nhận dựa trên mô hình.

obj = Model.find_by_id(params[:id])
obj.update_attribute :language, java

update_attribut

Phương thức này cập nhật nhiều thuộc tính của một đối tượng và cũng vượt qua xác nhận dựa trên mô hình.

attributes = {:name => BalaChandar”, :age => 23}
obj = Model.find_by_id(params[:id])
obj.update_attributes(attributes)

Hy vọng câu trả lời này sẽ làm rõ khi nào nên sử dụng phương pháp nào của hồ sơ hoạt động.


12

Cũng đáng chú ý là với update_attribute, thuộc tính mong muốn được cập nhật không cần phải được liệt kê màu trắng attr_accessibleđể cập nhật nó trái ngược với phương pháp gán khối lượng update_attributessẽ chỉ cập nhật attr_accessiblecác thuộc tính được chỉ định.


8

update_attribute chỉ cần cập nhật chỉ một thuộc tính của mô hình, nhưng chúng ta có thể chuyển nhiều thuộc tính trong update_attributes phương thức.

Thí dụ:

user = User.last

#update_attribute
user.update_attribute(:status, "active")

Nó vượt qua xác nhận

#update_attributes
user.update_attributes(first_name: 'update name', status: "active")

nó không cập nhật nếu xác nhận thất bại.


Giải thích rất tốt. Cảm ơn!
Diego Somar

6

Câu trả lời tuyệt vời. lưu ý rằng đối với ruby ​​1.9 trở lên, bạn có thể (và tôi nghĩ nên) sử dụng cú pháp băm mới cho update_attribut:

Model.update_attributes(column1: "data", column2: "data")

6

Bạn có thể quan tâm đến việc truy cập bài đăng trên blog này liên quan đến tất cả các cách có thể để gán thuộc tính hoặc bản ghi cập nhật (được cập nhật lên Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attribut-in-activerecord/ . Ví dụ, nó khác về các khía cạnh như chạy xác nhận, chạm vào update_at của đối tượng hoặc kích hoạt các cuộc gọi lại.

Như một câu trả lời cho câu hỏi của OP update_attributekhông bằng cách vượt qua các cuộc gọi lại.


Phải, tôi đã sửa đổi câu trả lời. Cảm ơn vì bạn đã phản hồi.
adamliesko 14/07/2015

4

update_attributeupdate_attributestương tự nhau, nhưng với một điểm khác biệt lớn: update_attribute không chạy xác nhận.

Cũng thế:

  • update_attributeđược sử dụng để cập nhật hồ sơ với thuộc tính duy nhất .

    Model.update_attribute(:column_name, column_value1)
  • update_attributesđược sử dụng để cập nhật hồ sơ với nhiều thuộc tính.

    Model.update_attributes(:column_name1 => column_value1, :column_name2 => column_value2, ...)

Hai phương pháp này thực sự dễ nhầm lẫn với tên và tác phẩm tương tự của chúng. Do đó, update_attributeđang được gỡ bỏ để ủng hộupdate_column .

Bây giờ, trong Rails4, bạn có thể sử dụng Model.update_column(:column_name, column_value)tại nơiModel.update_attribute(:column_name, column_value)

Nhấn vào đây để có thêm thông tin về update_column.


4

Để trả lời câu hỏi của bạn, update_attributebỏ qua lưu "xác nhận" nhưng nó vẫn chạy bất kỳ cuộc gọi lại nào khác như after_savev.v. Vì vậy, nếu bạn thực sự muốn "chỉ cập nhật cột và bỏ qua bất kỳ hành trình AR" nào thì bạn cần sử dụng (rõ ràng)

Model.update_all(...)xem https://stackoverflow.com/a/7243777/32453


2

Gần đây tôi gặp vấn đề update_attributeso với update_attributesvà xác nhận, tên tương tự, hành vi khác nhau, rất khó hiểu.

Để vượt qua hàm băm update_attributevà bỏ qua xác nhận, bạn có thể làm:

object = Object.new
object.attributes = {
  field1: 'value',
  field2: 'value2',
  field3: 'value3'
}
object.save!(validate: false)

1

Tôi nghĩ rằng câu hỏi của bạn là nếu có update_attribution trong before_save sẽ dẫn đến và vòng lặp vô tận (của các cuộc gọi update_attribution trong các cuộc gọi lại before_save, ban đầu được kích hoạt bởi một cuộc gọi update_attribution)

Tôi khá chắc chắn rằng nó bỏ qua cuộc gọi lại before_save vì nó không thực sự lưu bản ghi. Bạn cũng có thể lưu bản ghi mà không kích hoạt xác nhận bằng cách sử dụng

Model.save sai

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.