【问题标题】:Using Rails Form Helpers with Serialized Custom Classes使用带有序列化自定义类的 Rails 表单助手
【发布时间】:2011-04-15 09:35:30
【问题描述】:

我正在尝试将选项哈希值保存在单个数据库字段中。该表单能够将数据保存到数据库,但当我去编辑它时无法再次检索它(例如,除了 wp_options 字段之外的所有其他字段都已预先填充)。

class Profile < ActiveRecord::Base  
 serialize :wp_options  
end

这是我的自定义类:

class WP_Options
 attr_accessor :wp_name, :wp_desc, :wp_limit
end

以我的形式:

<%= form_for(@profile, :remote => true) do |f| %>
 ...
   <%= f.fields_for :wp_options do |wp_options| %>
      <%= wp_options.text_field :wp_name  %>
   <% end %>
 ...

在我的控制器中:

@profile = Profile.new(:wp_options => WP_Options.new)

在我的数据库列“wp_options”中:

--- !map:ActiveSupport::HashWithIndifferentAccess 
wp_name: Test  

任何建议将不胜感激。

【问题讨论】:

    标签: ruby-on-rails ruby serialization activerecord ruby-on-rails-3


    【解决方案1】:

    其实很简单。您需要使用带有reader 方法的类。您可以使用不同的方式创建它,但最简单的一种是使用OpenStruct 类(注意,它将无法看到 OpenStruct 的实例方法中的字段...此类无法重新定义方法)。

    在您的表单中,您应该添加:

    <%= f.fields_for :wp_options, @profile.wp_options do |wp_options| %>
    

    您可以使用f.object.wp_options 而不是@profile(如果您有动态变量)。

    对于模型Profile,您应该添加wp_options 方法。

    def wp_options
      OpenStruct.new(self.attributes['wp_options'])
    end
    

    在这种情况下,它仅在您的序列化 wp_options 是 Hash 类时才有效。

    希望对您有所帮助。

    PS。我使用了相同的技术,但是因为我有 type 哈希键,OpenStruct 无法创建它,所以我使用了简单的 Struct 类。我有data 专栏:

    def data
      keys = current_data.keys
      data = attributes[:data]
      Struct.new(*keys).new(*keys.map { |k| data[k] })
    end
    

    稍微不那么琐碎,但无论如何都是相同的方法(在此之前我创建了特殊类,但现在我知道 Struct 是创建此类东西的更好方法。更多想法可以在这里找到:How do I use hash keys as methods on a class? )

    【讨论】:

    • 我需要我的 wp_options 等价物作为散列保留,这样我就可以遍历它的条目。所以我没有对模型进行任何更改,而是将OpenStruct.new 放入如下形式: 也许它有窥视模型实现的视图,但它只知道 wp_options 是一个哈希而不是一个带有 attr 方法的对象。
    【解决方案2】:

    我遇到了同样的问题。我的解决方案如下:

    1. 在你的助手中定义一个方法:

      def wp_options_text_field(profile, wp_options, name)
        wp_options.text_field name, :value => profile.wp_options[name]
      end
      
    2. 在你看来:

      <%= form_for(@profile, :remote => true) do |f| %>
      ...
      <%= f.fields_for :wp_options do |wp_options| %>
        <%= wp_options_text_field :wp_name  %>
      <% end %>
      ...
      

    这里唯一的问题是您需要为您将使用的每个辅助方法定义方法。就我而言,我只使用了 2 种方法,而且并不痛苦。

    【讨论】:

      【解决方案3】:

      对于那些使用 Dmitry 解决方案的人,在 rails 3.0.5 上(不确定上一个/下一个版本,所以请先尝试),添加

      require 'ostruct'
      

      添加到您的 environment.rb 文件中以包含 OpenStruct。

      如果您要使用 JSON 进行序列化,请在您的模型中添加(哦,我对 RoR 还很陌生,所以请随时仔细检查并提出比这个更好的“有效”解决方案)(我的变量名称已更改为与上面的示例匹配):

      before_save :json_serialize
      after_save  :json_deserialize
      after_find  :json_deserialize
      
      def json_serialize  
        self.wp_options = ActiveSupport::JSON.encode(self.attributes['wp_options'])
      end
      
      def json_deserialize
        unless (self.attributes['wp_options'].nil?)
          self.wp_options = ActiveSupport::JSON.decode(self.attributes['wp_options'].to_s)
        end
      end
      

      最后一点:老实说,我不确定为什么必须将其存储在 self.wp_options 而不是 self.attributes['wp_options'] 中,如果有人能解释一下会很酷.

      【讨论】:

        猜你喜欢
        • 2011-12-16
        • 2011-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-29
        • 2017-08-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多