programing tip

양식에서 Rails 직렬화 된 필드를 편집하는 방법은 무엇입니까?

itbloger 2020. 12. 29. 06:45
반응형

양식에서 Rails 직렬화 된 필드를 편집하는 방법은 무엇입니까?


직렬화 된 필드가있는 Rails 프로젝트에 데이터 모델이 있습니다.

class Widget < ActiveRecord::Base
  serialize :options
end

옵션 필드에는 가변 데이터 정보가있을 수 있습니다. 예를 들어, 다음은 조명기 파일의 한 레코드에 대한 옵션 필드입니다.

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

내 질문은 사용자가 표준 양식보기에서이 정보를 편집 할 수있는 적절한 방법은 무엇입니까?

옵션 필드에 간단한 텍스트 영역 필드를 사용하는 경우 yaml 덤프 표현 만 얻고 해당 데이터는 문자열로 다시 전송됩니다.

Rails에서 이와 같이 직렬화 된 해시 필드를 편집하는 가장 좋은 / 적절한 방법은 무엇입니까?


옵션 키가 무엇인지 미리 알고 있다면 다음과 같이 특수 게터 및 세터를 선언 할 수 있습니다.

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

이것에 대한 좋은 점은 옵션 배열의 구성 요소를 속성으로 노출하여 Rails 양식 도우미를 다음과 같이 사용할 수 있다는 것입니다.

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

글쎄, 나는 같은 문제가 있었고 그것을 과도하게 설계하지 않으려 고 노력했다. 문제는 직렬화 된 해시를 fields_for에 전달할 수 있지만 함수에 대한 필드는 이것이 옵션 해시 (객체가 아님)라고 생각하고 양식 객체를 nil로 설정한다는 것입니다. 즉, 값을 편집 할 수 있지만 편집 후에는 나타나지 않습니다. 버그 또는 레일의 예기치 않은 동작 일 수 있으며 향후 수정 될 수 있습니다.

그러나 지금은 작동시키기가 아주 쉽습니다 (아침 내내 알아 내는데 시간이 걸렸지 만).

모델을 그대로 둘 수 있으며 뷰에서 객체에 대한 필드를 열린 구조체로 제공해야합니다. 그러면 레코드 개체가 올바르게 설정되고 (f2.object가 옵션을 반환 함) 두 번째로 text_field 빌더가 개체 / 매개 변수의 값에 액세스 할 수 있습니다.

"|| {}"를 포함 했으므로 새 / 만들기 양식에서도 작동합니다.

= 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

좋은 하루 되세요


emh가 거의 다 왔습니다. Rails가 양식 필드에 값을 반환한다고 생각하지만 그렇지 않습니다. 따라서 각 필드의 ": value =>"매개 변수에 수동으로 입력 할 수 있습니다. 매끄럽게 보이지는 않지만 작동합니다.

여기에서 위에서 아래로 :

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 %>

"fields_for"에 추가하는 모든 필드는 직렬화 된 해시에 표시됩니다. 원하는대로 필드를 추가하거나 제거 할 수 있습니다. "옵션"해시에 속성으로 전달되고 YAML로 저장됩니다.


나는 매우 유사한 문제로 고심하고 있습니다. 여기서 찾은 솔루션은 나에게 매우 도움이되었습니다. @austinfromboston, @ Christian-Butske, @sbzoom 및 다른 모든 분들께 감사드립니다. 그러나 이러한 답변은 약간 오래되었을 수 있습니다. Rails 5와 ruby ​​2.3에서 저에게 도움이 된 것은 다음과 같습니다.

의 형태의:

<%= 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 %>

그런 다음 컨트롤러에서 다음과 같이 강력한 매개 변수를 업데이트해야했습니다.

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

직렬화 된 해시 매개 변수가 매개 변수 목록의 끝에 오는 것이 중요해 보입니다. 그렇지 않으면 Rails는 다음 매개 변수도 직렬화 된 해시 일 것으로 예상합니다.

보기에서 간단한 if / then 논리를 사용하여 해시가 비어 있지 않은 경우에만 표시 한 다음 값이 nil이 아닌 키 / 값 쌍만 표시했습니다.


세터 / 게터가 필요하지 않습니다. 방금 모델에서 정의했습니다.

serialize :content_hash, Hash

그런 다음 뷰에서 다음을 수행합니다 (simple_form 사용하지만 vanilla 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 last issue is how to let the user add a new key/value pair.


I will suggest something simple, because all the time, when user will save form You will get string. So You can use for example before filter and parse those data like that:

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

of course You should add validation if this is correct YAML. But it should works.


I'm trying to do something similar and I found this sort of works:

<%= 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 %>

except that the form fields aren't populated when the form is rendered. when the form is submitted the values come through just fine and i can do:

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

so its "half" working...


I was facing the same issue, after some research i found a solution using Rails' store_accessor to make keys of a serialized column accessible as attributes.

With this we can access "nested" attributes of a serialized column …

# post.rb
class Post < ApplicationRecord
  serialize :options
  store_accessor :options, :value1, :value2, :value3
end

# set / get values
post = Post.new
post.value1 = "foo"
post.value1
#=> "foo"
post.options['value1']
#=> "foo"

# strong parameters in posts_controller.rb
params.require(:post).permit(:value1, :value2, :value3)

# form.html.erb
<%= form_with model: @post, local: true do |f| %>
  <%= f.label :value1 %>
  <%= f.text_field :value1 %>
  # …
<% end %>

ReferenceURL : https://stackoverflow.com/questions/1002963/how-to-edit-a-rails-serialized-field-in-a-form

반응형