2011-01-06 31 views
26

Tôi có một câu lệnh tạo cho một số kiểu máy, nhưng nó tạo ra một bản ghi trong bảng nối bất kể bản ghi đã tồn tại chưa.Trong Rails, cách tốt nhất để cập nhật một bản ghi hoặc tạo một bản ghi mới nếu nó không tồn tại là gì?

Đây là những gì mã của tôi trông giống như:

@user = User.find(current_user) 
@event = Event.find(params[:id]) 
for interest in @event.interests 
@user.choices.create(:interest => interest, :score => 4) 
end 

Vấn đề là nó tạo ra các hồ sơ không có vấn đề gì. Tôi muốn nó tạo ra một kỷ lục chỉ khi không có hồ sơ đã tồn tại; nếu một bản ghi không tồn tại, tôi muốn nó lấy thuộc tính của bản ghi được tìm thấy và cộng hoặc trừ 1.

Tôi đã nhìn xung quanh đã thấy một cái gì đó gọi là find_or_create_by. Điều này làm gì khi tìm thấy một bản ghi? Tôi muốn nó lấy thuộc tính hiện tại :score và thêm 1.

Có thể tìm hoặc tạo bởi id? Tôi không chắc chắn thuộc tính nào tôi sẽ tìm thấy, vì mô hình tôi đang xem là mô hình tham gia chỉ có id khóa ngoại và thuộc tính điểm.

tôi đã cố gắng

@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4) 

nhưng có

phương pháp xác định find_by_user

Tôi nên làm gì?

+1

là CURRENT_USER đã một thể hiện của mô hình tài khoản? Nếu vậy, bạn không cần phải tìm lại nó và chỉ có thể sử dụng 'current_user' thay cho' @user = ... '. –

Trả lời

23

Giả sử rằng mô hình Choiceuser_id (để kết hợp với một người dùng) và một interest_id (liên kết với một lãi), một cái gì đó như thế này nên làm như lừa:

@user = User.find(current_user) 
@event = Event.find(params[:id]) 

@event.interests.each do |interest| 
    choice = @user.choices.find_or_initialize_by_interest_id(interest.id) do |c| 
    c.score = 0 # Or whatever you want the initial value to be - 1 
    end 

    choice.score += 1 
    choice.save! 
end 

Một số lưu ý:

  1. Bạn không cần phải bao gồm cột user_id trong find_or_*_by_*, vì bạn đã hướng dẫn Rails chỉ tìm nạp choices thuộc về @user.
  2. Tôi đang sử dụng find_or_initialize_by_*, cơ bản giống như find_or_create_by_*, với một khác biệt chính là initialize không thực sự tạo bản ghi. Điều này sẽ tương tự như Model.new như trái ngược với Model.create.
  3. Khối đặt c.score = 0 chỉ được thực hiện nếu bản ghi không không phải là tồn tại.
  4. choice.score += 1 sẽ cập nhật giá trị điểm cho bản ghi, bất kể nó có tồn tại hay không. Do đó, điểm số mặc định c.score = 0 phải là giá trị ban đầu trừ đi một.
  5. Cuối cùng, choice.save! sẽ cập nhật bản ghi (nếu nó đã tồn tại) hoặc tạo bản ghi bắt đầu (nếu không).
+0

liên kết câu hỏi tương tự này http://stackoverflow.com/questions/18747062/rails-create-or-update-magic – fatman13

+0

Câu trả lời này phải được cập nhật, một số phương pháp không phù hợp với đường ray 4 –

7

find_or_create_by_user_id âm thanh tốt hơn

+0

Sự khác biệt tho là gì? – MartinElvar

+1

điều này không cập nhật hồ sơ? Nó tìm thấy nó, hoặc nó tạo ra nó. – baash05

59
my_class = ClassName.find_or_initialize_by_name(name) 

my_class.update_attributes({ 
    :street_address => self.street_address, 
    :city_name => self.city_name, 
    :zip_code => self.zip_code 
}) 
+0

Tại sao bỏ phiếu? –

+6

không chắc chắn lý do tại sao điều này đã được giảm giá. điều này rất hữu ích cho tôi - cảm ơn vì sự đóng góp! – shedd

+0

Tôi cũng thấy nó hữu ích. Tôi đoán rằng downvote là vì nó chỉ giải quyết một phần những gì OP đang hỏi. –

0

Nếu bạn đang sử dụng đường ray 4 Tôi không nghĩ rằng nó tạo ra các phương thức tìm kiếm như trước đây, do đó find_or_create_by_user không được tạo cho bạn. Thay vào đó bạn muốn làm điều đó như thế này:

@user = User.find(current_user) 
@event = Event.find(params[:id]) 
for interest in @event.interests 
@user.choices.find_or_create_by(:interest => interest) do |c| 
    c.score ||= 0 
    c.score += 1 
end 
end 
3

Ngoài ra, trong Rails 3 bạn có thể làm:

@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create 
+0

'first_or_create' được ưu tiên trong Rails 4 trong khi đó 'find_or_intialize_by_xxx (thuộc tính)' bị phản đối vì lợi ích của 'find_or_intialize_by (xxx: attribute)' –

0

Trong Rails 4 Bạn có thể sử dụng find_or_create_by để có được một đối tượng (nếu không tồn tại, nó sẽ tạo ra), sau đó sử dụng update để lưu hoặc cập nhật bản ghi, phương thức cập nhật sẽ tiếp tục ghi nếu nó không tồn tại, nếu không cập nhật bản ghi.

Ví dụ

@edu = current_user.member_edu_basics.find_or_create_by(params.require(:member).permit(:school)) 

if @edu.update(params.require(:member).permit(:school, :majoy, :started, :ended)) 
Các vấn đề liên quan