如何在形式编辑Rails的序列化的领域?(How to edit a Rails serialize

2019-06-23 09:59发布

我在那有一个序列化的领域我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的编辑这样的序列化的哈希领域最好的/合适的方法是什么?

Answer 1:

如果你知道什么选项键将要提前,你可以像这样特别声明getter和setter方法为他们:

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


Answer 2:

嗯,我有同样的问题,并试图不要过度设计它。 问题是,尽管可以通过序列化的哈希fields_for,对于功能的领域会认为,这是一个选项哈希(而不是你的对象),并设置表单对象为零。 这意味着,虽然你可以编辑的值,他们不会编辑后出现。 这可能是一个错误或轨道意外的行为,也许固定在未来。

然而,就目前而言,这是很容易得到它的工作(尽管它整个上午带我去弄清楚)。

您可以留下您模型是和在视图中,你需要给字段的对象作为一个开放的结构。 这将正确地设置记录对象(所以f2.object将返回你的选择),其次它可以让text_field建设者从访问你的对象/ PARAMS的值。

自从我列入“|| {}”,它将与新/创建表单的工作了。

= 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

祝你有美好的一天



Answer 3:

EMH是几乎没有。 我认为Rails的将值返回到窗体字段,但事实并非如此。 所以,你可以把它放在那里手动在“:价值=>”为每个字段参数。 它不漂亮的外观,但它的工作原理。

这是从上到下:

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。



Answer 4:

我一直在挣扎了非常类似的问题。 我发现这里的解决方案是对我很有帮助。 谢谢@austinfromboston,@基督教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逻辑只显示散列,如果它不是空的,然后仅显示键/值对,其中值不是零。



Answer 5:

无需二传手/ getter方法,我只是在模型中定义:

serialize :content_hash, Hash

然后在视图中,我这样做(与simple_form,但香草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}

我最后的问题是如何让用户添加一个新的键/值对。



Answer 6:

我会建议一些简单的,因为所有的时间,当用户将节省形成你将得到的字符串。 所以你可以使用例如过滤器之前和解析像这样的数据:

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

当然,你应该添加验证这是否是正确的YAML。 但它应该工作。



Answer 7:

我试图做同样的事情,我发现这种作品:

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

除了当表单呈现的表单字段不填充。 当表单提交的值来通过就好了,我可以这样做:

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

所以它的“半壁江山”的工作...



Answer 8:

我正面临同样的问题,经过一番研究,我发现,使用Rails的一个解决方案store_accessor使作为属性访问的序列化列的密钥。

有了这个,我们可以访问序列化列的“嵌套”的属性...

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


文章来源: How to edit a Rails serialized field in a form?