Ruby on Rails: Xóa nhiều khóa băm


148

Tôi thường thấy mình viết điều này:

params.delete(:controller)  
params.delete(:action)  
params.delete(:other_key)  
redirect_to my_path(params)  

Dấu vết xóa không cảm thấy đúng và cũng không:

[:controller, :action, :other_key].each do |k|
  params.delete(k)
end

Có điều gì đơn giản và sạch sẽ hơn?


Khi tôi viết rằng cách tiếp cận thứ hai không cảm thấy đúng, tôi có nghĩa là với sự phong phú của API Hash, tôi đã nghi ngờ rằng đã có một phương pháp hoặc thành ngữ nào đó cho điều này và một bản vá khỉ sẽ không cần thiết. Có lẽ không, mặc dù. Rất cám ơn tất cả những người đã trả lời!
Mark Westling

3
Hash # ngoại trừ chính xác là những gì tôi đang tìm kiếm. Tôi không nhớ rằng đó là tiện ích mở rộng lõi Rails nên tôi đã rất bối rối khi không thể tìm thấy nó trong API Hash.
Đánh dấu Westling

1
Lưu ý rằng câu trả lời đúng là Hash#except!nhưng Hash#exceptlà cách để đi (đừng lộn xộn params!). Theo nguyên tắc thông thường, không gây rối với bất kỳ đối tượng nào tại chỗ trừ khi hoàn toàn bắt buộc, các tác dụng phụ có thể có kết quả không mong muốn.
tokland

Câu trả lời:


219

Tôi đoán bạn không biết về Hash # ngoại trừ phương thức ActiveSupport thêm vào Hash.

Nó sẽ cho phép mã của bạn được đơn giản hóa thành:

redirect_to my_path(params.except(:controller, :action, :other_key))

Ngoài ra, bạn sẽ không phải vá khỉ, vì nhóm Rails đã làm điều đó cho bạn!


1
Ahhh, tôi biết tôi đã nhìn thấy điều này trước đây nhưng tôi không thể nhớ nơi nào! (Do đó nhận xét "điều này không cảm thấy đúng" của tôi.) Cảm ơn!
Đánh dấu Westling

3
Một trong những phương pháp ít tài liệu hơn. Tôi đã đi tìm một cái gì đó như thế này trong khi đề xuất một câu trả lời nhưng không thấy nó.
tadman

1
Vì một số lý do ngoại trừ không làm việc. Nhưng except!đã làm. Rails 3.0
Chuyến đi

4
Rails 3.2 trên các thuộc tính ActiveRecord, có phải sử dụng chuỗi cho các khóa không? tức là User.attributes.except("id", "created_at", "updated_at")các biểu tượng không hoạt động
house9

1
Thêm vào những gì @ house9 đã đề cập, attributesphương thức ActiveRecord trả về một Hashkhóa có String. Vì vậy, sau đó bạn sẽ phải sử dụng tên khóa chuỗi trong .except(). Tuy nhiên, tôi giải quyết vấn đề này bằng cách sử dụng Hash.symbolize_keysla @user.attributes.symbolize_keys.except(:password, :notes)- sử dụng symbolize_keyslàm cho nó hoạt động như người ta mong đợi
FireDragon

44

Trong khi sử dụng Hash#exceptxử lý vấn đề của bạn, hãy biết rằng nó giới thiệu các vấn đề bảo mật tiềm năng . Một nguyên tắc nhỏ để xử lý bất kỳ dữ liệu nào từ khách truy cập là sử dụng phương pháp danh sách trắng. Trong trường hợp này, sử dụng Hash#slicethay thế.

params.slice!(:param_to_remove_1, :param_to_remove_2)
redirect_to my_path(params)

1
Cảm ơn đã đề cập đến các vấn đề an ninh xung quanh chuyển hướng.
David J.

12
Chỉ cần ngẩng cao đầu: ActiveSupport, không phải chính Ruby, cung cấp Hash # lát và #slice! as.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/...
David J.

1
Tôi không thể nhận được liên kết David James với công việc nhưng điều này có vẻ là ok: api.rubyonrails.org/classes/Hash.html#method-i-slice
Dominic Sayers

phương pháp không xác định 'lát!' cho{:b=>2, :c=>3}:Hash
Khurram Raza

25

Tôi hoàn toàn hài lòng với mã ban đầu bạn đăng trong câu hỏi của bạn.

[:controller, :action, :other_key].each { |k| params.delete(k) }

mà không sửa đổi Hashđây là câu trả lời tốt nhất: +1:
Dan Bradbury

Tôi đã sử dụng phương pháp này nhưng thay thế params bằng tên của hàm băm và sau đó nó hoạt động !! Băm bị đột biến.
Pablo

13

Một cách khác để diễn đạt câu trả lời của dmathieu có thể là

params.delete_if { |k,v| [:controller, :action, :other_key].include? k }

8

Cháy lên một bản vá khỉ?

class Hash
  def delete_keys!(*keys)
    keys.flatten.each do |k|
      delete(k)
    end

    self
  end

  def delete_keys(*keys)
    _dup = dup
    keys.flatten.each do |k|
      _dup.delete(k)
    end

    _dup
  end
end

5
Khỉ vá là một công cụ của phương sách cuối cùng.
Bob Aman

15
Khỉ vá thay thế các chức năng hiện có là một công cụ cuối cùng. Các bản vá khỉ có thêm chức năng mới là Ruby 101.
David Seiler

4
Nên delete(k)thay thếdelete(key)
Vincent

Để bảo trì mã, việc thực hiện không phá hủy delete_keyschỉ đơn giản làdup.delete_keys!(*keys)
Phrogz

@Phrogz Xác định một khía cạnh khác không phải là một ý tưởng tồi, nhưng nó chỉ để lại ở đây không được kiểm soát cho rõ ràng.
tadman

2

Tôi không biết những gì bạn nghĩ là sai với giải pháp đề xuất của bạn. Tôi cho rằng bạn muốn một delete_allphương thức trên Hash hoặc một cái gì đó? Nếu vậy, câu trả lời của tadman cung cấp giải pháp. Nhưng thẳng thắn mà nói, một lần, tôi nghĩ giải pháp của bạn cực kỳ dễ thực hiện. Nếu bạn đang sử dụng điều này thường xuyên, bạn có thể muốn gói nó trong một phương thức trợ giúp.

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.