2012-07-14 35 views
17

Tôi đang sử dụng đá quý nested_form cho mối quan hệ AddressBook của mình. Khi những khoảng trống sử dụng ra giá trị của một hiện Addr, tôi muốn xóa Addr hơn là tiết kiệm với một trống valuecách tránh lưu bản ghi trống trên biểu mẫu đường ray lồng nhau

class Person < ActiveRecord::Base 
    has_many :addrs, dependent: :destroy 
    attr_accessible :name, :addrs_attributes 
    accepts_nested_attributes_for :addrs, reject_if: :addr_blank, allow_destroy: true 

    def addr_blank(a) 
    valid? && a[:id].blank? && a[:value].blank? 
    end 

class Addr < ActiveRecord::Base 
    belongs_to :person 
    attr_accessible :kind, :label, :value, :person_id 

phương pháp :reject_if tôi hoạt động tốt nhưng nó không cho tôi tất cả mọi thứ tôi cần

  1. valid? giữ Addrs trống của tôi xung quanh thông qua xác nhận
  2. a[:id].blank? tránh bị từ chối khi những khoảng trống sử dụng ra và ghi lại hiện

Bây giờ, tôi cần phải xóa (thay vì lưu) một số hiện tại Addr khi người dùng điền vào value. Ngoài ra, tôi đang trưng bày Persons và Addrs thông qua API RESTful. Tôi thấy hai tùy chọn có thể có:

  1. &hl=vi băm để thêm phép thuật _destroy=1 param. IOW, mô phỏng hoạt động của người dùng bằng cách nhấn nút xóa.
  2. Đóng gói phần này bên trong mô hình Addr sao cho bản cập nhật có số trống value được coi là xóa hiệu quả.

Dựa trên những lời khuyên ở đây là làm thế nào tôi thực hiện nó:

people_controller.rb

def update 
    @person = Person.find(params[:id]) 
    @person.destroy_blank_addrs(params[:person]) 
    respond_to do |format| 
    ... 

person.rb

def destroy_blank_addrs(person_params) 
    if valid? && person_params[:addrs_attributes] 
    person_params[:addrs_attributes].each do |addr_params_array| 
     addr_params= addr_params_array[1] 
     addr_params[:_destroy] = '1' if !addr_params[:id].blank? && addr_params[:value].blank? 
    end 
    end 
end 
+0

Trong hai, sử dụng tùy chọn 1. Bạn không muốn "kỳ diệu" like "nếu giá trị của trường X là trống sau đó xóa các kỷ lục". – Zabba

+0

Tôi đã cập nhật câu hỏi với giải pháp bạn đã đề xuất. –

+0

@Zabba, tôi đang tái cấu trúc mã này sau 18 tháng và bạn đã đúng. Ý tưởng của tôi về việc tẩy trống giá trị như một "phép thuật" phá hủy_addrs' là não chết. Tôi cũng tin rằng bất kỳ giải pháp nào liên quan trực tiếp đến việc sửa đổi mảng 'params' là thực hành không tốt. Bất kỳ xử lý hậu xử lý nào phải được thực hiện sau 'assign_attributes' nhưng trước khi' lưu' –

Trả lời

5

Một lựa chọn thứ ba sẽ là để thêm một cuộc gọi lại before_save trên Perso n sẽ xóa tất cả các địa chỉ trống. Ý tưởng này có một số công đức, nhưng tôi có lẽ sẽ không đi với nó.

Trong số hai tùy chọn bạn trình bày, tôi sẽ không xử lý các thông số sau xử lý. Nó sẽ hoạt động, nhưng nó là quá nhiều công việc. Bên cạnh đó, để mã điều khiển sẽ nhận được một chút lộn xộn và tôi là một người tin tưởng vững chắc trong một bộ điều khiển rất mỏng.

Tùy chọn dễ nhất, trong đầu, là xóa các địa chỉ trống sau khi lưu. Bạn có thể thêm Person#remove_blank_addresses() và sau đó gọi nó để lưu thành công. Bạn không cần truyền các tham số - nó chỉ có thể lặp lại các địa chỉ và loại bỏ các địa chỉ trống. Nó có những bất lợi của việc tạo ra các địa chỉ rỗng và sau đó phá hủy chúng, nhưng bạn sẽ cần nó để cập nhật mọi người.

Nếu chúng ta đang nói về giải pháp sạch nhất (theo ý kiến ​​của tôi), tôi sẽ giới thiệu một lớp thứ ba có thể xử lý tất cả logic đó và có bộ điều khiển ủy quyền cho nó. Bộ điều khiển sẽ dễ dàng đủ để kiểm tra trong sự cô lập và sau đó bạn có thể viết một mô hình spec để kiểm tra tất cả các chi tiết nitty-gritty. Đó là một công việc nhiều hơn một chút và tôi không thể nghĩ ra một cái tên tốt ngay bây giờ (PersonUpdater?), Nhưng nó có thể là một ý tưởng đáng suy nghĩ về.

+1

Cảm ơn bạn đã trả lời chu đáo, Stefan. Lớp 3 là giải pháp sạch nhất, nhưng quá nhiều nỗ lực. Ý tưởng đưa bản ghi vào db có sẵn cho một số quá trình không đồng bộ (thậm chí chỉ trong một khoảnh khắc) có vẻ sai. Một ý tưởng khác là quản lý nó trên giao diện người dùng trong JS. Làm trống chỉ là một cách khác để nhấn nút xóa. Sau đó Blanking không bao giờ biến nó thành api REST của tôi. –

+0

Trong trường hợp đó, tôi sẽ có mã này trong bộ điều khiển. Nó là một chút phức tạp hơn để kiểm tra và bằng cách nào đó trông lộn xộn trong niềm tin của tôi về những gì cần được trong bộ điều khiển, nhưng nó phải là giải pháp sạch nhất trong trường hợp của bạn. –

+0

Cảm ơn, tôi đã đi với phương pháp điều khiển bởi vì tôi cảm thấy nó đơn giản hơn và bổ sung chức năng cho API của tôi, nơi người tiêu dùng có thể xóa Addrs bằng cách xóa giá trị. Nếu bạn cập nhật câu trả lời của bạn, tôi sẽ chấp nhận. –

14
accepts_nested_attributes_for :addrs, 
    allow_destroy: true, 
    :reject_if => proc { |att| att[:name].blank? && attr[:description].blank? } 
8
accepts_nested_attributes_for :addrs, 
    allow_destroy: true, 
    reject_if: -> { |attr| [name, description].any? &:blank? } 
+0

Rất ngắn gọn. Tôi bao gồm một thử nghiệm 'hợp lệ?' Để các hàng không bị từ chối cho đến khi người dùng được thực hiện giải quyết các xác nhận hợp lệ. –

1
accepts_nested_attributes_for :addrs, 
    allow_destroy: true, 
    reject_if: :all_blank 
+0

Cho phép bạn chỉ định một Proc hoặc một Symbol trỏ đến một phương thức kiểm tra xem một bản ghi có nên được xây dựng cho một băm thuộc tính nào đó hay không. Hàm băm được chuyển tới Proc được cung cấp hoặc phương thức và nó sẽ trả về true hoặc false. Khi không: reject_if được chỉ định, một bản ghi sẽ được xây dựng cho tất cả các băm thuộc tính không có giá trị _destroy đánh giá là đúng. Đi qua: all_blank thay vì một Proc sẽ tạo ra một proc sẽ từ chối một bản ghi mà tất cả các thuộc tính được để trống, không bao gồm bất kỳ giá trị nào cho _destroy. – hadees

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