2009-06-16 31 views
50

Tôi có một mô hình dữ liệu trong dự án Rails của tôi rằng có một trường serialized:Làm thế nào để chỉnh sửa trường Rails được tuần tự hóa trong một biểu mẫu?

class Widget < ActiveRecord::Base 
    serialize :options 
end 

Trường tùy chọn có thể có biến thông tin dữ liệu. Ví dụ: đây là trường tùy chọn cho một bản ghi từ tệp đồ đạc:

options: 
    query_id: 2 
    axis_y: 'percent' 
    axis_x: 'text' 
    units: '%' 
    css_class: 'occupancy' 
    dom_hook: '#average-occupancy-by-day' 
    table_scale: 1 

Câu hỏi của tôi là cách thích hợp để người dùng chỉnh sửa thông tin này trong chế độ xem biểu mẫu chuẩn?

Nếu bạn chỉ sử dụng trường văn bản đơn giản cho trường tùy chọn, bạn sẽ chỉ nhận được biểu diễn kết xuất yaml và dữ liệu đó sẽ được gửi lại dưới dạng chuỗi.

Cách tốt nhất/thích hợp để chỉnh sửa trường băm được tuần tự hóa như thế này trong Rails là gì?

+0

Bạn muốn giao diện loại nào? Nên có các trường cho mỗi thuộc tính? Bạn có biết tất cả các thuộc tính đều ở phía trước không? –

+0

Tất cả các thuộc tính sẽ không được biết trước. Một số là tiêu chuẩn và sẽ luôn có mặt nhưng phần còn lại có thể được người dùng xác định. Đây là giao diện chỉ dành cho quản trị viên, vì vậy tôi tin tưởng đầu vào của người dùng ở mức độ lớn hơn nhiều so với bình thường. Tôi thực sự chỉ sử dụng một hộp văn bản và cho phép người dùng nhập các cặp khóa: giá trị sử dụng đánh dấu YAML và nó hoạt động tốt theo cách thông qua – cpjolicoeur

Trả lời

55

Nếu bạn biết những gì các phím tùy chọn sẽ được trước, bạn có thể tuyên bố thu khí đặc biệt và setters cho họ như vậy:

class Widget < ActiveRecord::Base 
    serialize :options 

    def self.serialized_attr_accessor(*args) 
    args.each do |method_name| 
     eval " 
     def #{method_name} 
      (self.options || {})[:#{method_name}] 
     end 
     def #{method_name}=(value) 
      self.options ||= {} 
      self.options[:#{method_name}] = value 
     end 
     attr_accessible :#{method_name} 
     " 
    end 
    end 

    serialized_attr_accessor :query_id, :axis_y, :axis_x, :units 
end 

Những điều tốt đẹp về vấn đề này là nó cho thấy các thành phần của tùy chọn mảng như là thuộc tính, cho phép bạn sử dụng Rails tạo người giúp đỡ như vậy:

#haml 
- form_for @widget do |f| 
    = f.text_field :axis_y 
    = f.text_field :axis_x 
    = f.text_field :unit 
+0

Cảm ơn, nhưng tôi không biết tất cả các giá trị tùy chọn trước thời hạn. Một số người trong số họ sẽ luôn luôn có mặt, nhưng phần còn lại có thể được người dùng xác định. – cpjolicoeur

+0

Đúng, điều đó sẽ tuyệt vời để tạo những người truy cập động này – Artur79

+1

tốt của nó để thêm vào cuối của eval: attr_accessible method_name – Artur79

1

tôi đang cố gắng để làm một cái gì đó tương tự và tôi thấy điều này loại công trình:

<%= form_for @search do |f| %> 
    <%= f.fields_for :params, @search.params do |p| %> 
     <%= p.select "property_id", [[ "All", 0 ]] + PropertyType.all.collect { |pt| [ pt.value, pt.id ] } %> 

     <%= p.text_field :min_square_footage, :size => 10, :placeholder => "Min" %> 
     <%= p.text_field :max_square_footage, :size => 10, :placeholder => "Max" %> 
    <% end %> 
<% end %> 

ngoại trừ trường biểu mẫu không được điền khi biểu mẫu được hiển thị. khi biểu mẫu được gửi các giá trị đi qua chỉ tốt đẹp và tôi có thể làm:

@search = Search.new(params[:search]) 

như vậy "một nửa" của mình làm việc ...

28

EMH là gần như ở đó. Tôi sẽ nghĩ rằng Rails sẽ trả về các giá trị cho các trường biểu mẫu nhưng nó không. Vì vậy, bạn có thể chỉ cần đặt nó trong đó bằng tay trong tham số ": value =>" cho mỗi trường. Nó không trơn, nhưng nó hoạt động.

Dưới đây là từ trên xuống dưới:

class Widget < ActiveRecord::Base 
    serialize :options, Hash 
end 

<%= form_for :widget, @widget, :url => {:action => "update"}, :html => {:method => :put} do |f| %> 
<%= f.error_messages %> 
    <%= f.fields_for :options do |o| %> 
     <%= o.text_field :axis_x, :size => 10, :value => @widget.options["axis_x"] %> 
     <%= o.text_field :axis_y, :size => 10, :value => @widget.options["axis_y"] %> 
    <% end %> 
<% end %> 

Bất kỳ lĩnh vực bạn thêm trong "fields_for" sẽ hiển thị trong các hash serialized. Bạn có thể thêm hoặc xóa các trường theo ý muốn. Chúng sẽ được chuyển thành các thuộc tính cho hash "options" và được lưu trữ như YAML.

+0

Tôi đang cố gắng làm như bạn đã nói, nhưng nó dường như không làm việc cho tôi: http://stackoverflow.com/questions/6621341 –

1

Tôi sẽ đề xuất điều gì đó đơn giản, bởi vì mọi lúc, khi người dùng sẽ lưu biểu mẫu Bạn sẽ nhận được chuỗi. Vì vậy, bạn có thể sử dụng ví dụ trước khi lọc và phân tích cú pháp các dữ liệu như vậy:

before_save do 
    widget.options = YAML.parse(widget.options).to_ruby 
end 

tất nhiên Bạn nên thêm xác thực nếu đúng YAML. Nhưng nó sẽ hoạt động.

3

Không cần setter/getter, tôi chỉ được định nghĩa trong mô hình:

serialize :content_hash, Hash 

Sau đó, trong giao diện, tôi làm (với simple_form, nhưng tương tự với vani Rails):

= f.simple_fields_for :content_hash do |chf| 
    - @model_instance.content_hash.each_pair do |k,v| 
     =chf.input k.to_sym, :as => :string, :input_html => {:value => v} 

My vấn đề cuối cùng là cách cho phép người dùng thêm cặp khóa/giá trị mới.

+0

Chủ yếu là làm việc, ngoại trừ tôi đang đối phó với một băm sâu và chỉ có cấp độ gốc kết thúc lên như một băm với điều này. – cpuguy83

35

Vâng, tôi đã có cùng một vấn đề và cố gắng không quá kỹ sư. Vấn đề là, mặc dù bạn có thể chuyển băm serialized vào fields_for, các trường cho hàm sẽ nghĩ, nó là một tùy chọn hash (và không phải đối tượng của bạn), và thiết lập đối tượng form thành nil. Điều này có nghĩa, mặc dù bạn có thể chỉnh sửa các giá trị, chúng sẽ không xuất hiện sau khi chỉnh sửa. Nó có thể là một lỗi hoặc hành vi bất ngờ của đường ray và có thể cố định trong tương lai.

Tuy nhiên, hiện tại, nó khá dễ dàng để làm cho nó hoạt động (mặc dù nó đã cho tôi cả buổi sáng để tìm ra).

Bạn có thể để mô hình của bạn như hiện tại và trong giao diện bạn cần cung cấp cho các trường cho đối tượng dưới dạng cấu trúc mở. Điều đó sẽ thiết lập đúng đối tượng bản ghi (vì vậy f2.object sẽ trả về các tùy chọn của bạn) và thứ hai nó cho phép trình tạo text_field truy cập giá trị từ đối tượng/thông số của bạn.

Vì tôi đã bao gồm "|| {}", nó cũng sẽ hoạt động với các biểu mẫu mới/tạo.

= form_for @widget do |f| 
    = f.fields_for :options, OpenStruct.new(f.object.options || {}) do |f2| 
    = f2.text_field :axis_y 
    = f2.text_field :axis_x 
    = f2.text_field :unit 

Có một ngày tuyệt vời

+1

Thực hiện tốt. Mẹo này đã cứu tôi một thời gian tối nay. Tôi không nghĩ về thực tế rằng đối tượng là một băm sẽ có nghĩa là nó sẽ được hiểu là một băm tùy chọn, nhưng nếu đó thực sự là những gì đang xảy ra, thì nó có ý nghĩa rất nhiều. – Legion

+1

Tôi thực sự thực sự thích giải pháp này, tôi đã thêm điều này vào mô hình của mình để hoàn thành nó: 'def options OpenStruct.new self [: options] || {} kết thúc', vì vậy bạn có được OpenStruct luôn khi đọc thuộc tính .. –

+2

Tôi nghĩ có một lỗi nhỏ: bạn nên gọi 'text_field' trên' f2', không phải 'f' – Sidhannowe

4

Tôi đã đấu tranh với một vấn đề rất giống nhau. Các giải pháp tôi tìm thấy ở đây rất hữu ích cho tôi. Cảm ơn bạn @austinfromboston, @ Christian-Butske, @sbzoom và mọi người khác. Tuy nhiên, tôi nghĩ rằng những câu trả lời này có thể hơi lỗi thời. Đây là những gì làm việc cho tôi với Rails 5 và ruby ​​2.3:

Trong hình thức:

<%= f.label :options %> 
<%= f.fields_for :options do |o| %> 
    <%= o.label :axis_y %> 
    <%= o.text_field :axis_y %> 
    <%= o.label :axis_x %> 
    <%= o.text_field :axis_x %> 
    ... 
<% end %> 

và sau đó trong bộ điều khiển tôi phải cập nhật các thông số mạnh mẽ như vậy:

def widget_params 
    params.require(:widget).permit(:any, :regular, :parameters, :options => [:axis_y, :axis_x, ...]) 
end 

Nó có vẻ quan trọng là tham số băm được tuần tự hóa xuất hiện ở cuối danh sách tham số. Nếu không, Rails sẽ mong đợi tham số tiếp theo cũng là một băm được tuần tự hóa.

Trong chế độ xem, tôi đã sử dụng một số logic nếu/sau đó chỉ hiển thị băm nếu nó không rỗng và sau đó chỉ hiển thị cặp khóa/giá trị trong đó giá trị không phải là 0.

+0

Điều này làm việc để lưu trữ các giá trị, nhưng khi bạn mở biểu mẫu 'chỉnh sửa ', bạn không thấy các giá trị bạn đã lưu –

+0

@YaroShm Đã lâu rồi kể từ khi tôi truy cập vấn đề này. Khi tôi nhớ các thông số mạnh mẽ là một chút khôn lanh và cập nhật cho đường ray trong năm qua có thể đã thay đổi cú pháp cần thiết. Nó có lẽ sẽ mất một số gỡ lỗi cẩn thận và có thể một chút may mắn poking để làm cho nó hoạt động. Khi bạn làm, hãy đăng mẹo ở đây. Nó sẽ giúp các nhà phát triển khác tìm thấy bài đăng này trong tương lai. May mắn nhất! – JDenman6

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