【问题标题】:Storing List item details in a database?将列表项详细信息存储在数据库中?
【发布时间】:2018-01-10 12:06:13
【问题描述】:

所以,这可能更像是一个“软件工程”问题。但我正在考虑如何在活动记录中存储小部件的详细信息的好方法。

假装小部件 A 有一个显示页面,在那个显示页面中,我们有一些手风琴风格的“FAQS”或类似的东西。手风琴内部是一个列表,其中的要点突出了 Widget A 如何工作或如何使用 Widget A 的不同内容。

显然我们不想为每个小部件创建单独的页面,因此这些项目需要存储在某个地方。但我们也不想在数据库中为每个字段创建...10、20 或 30 个单独的字段。那么有什么解决办法呢?

我的第一个想法是某种散列或数组,但是 rails 允许这样做吗?特别是如果它们是每个项目的长字符串。有没有更好的办法?

或者是正确的方法只是将其声明为模型(如..“faq_item”)或其他东西,然后为它需要去的 Widget 提供一个参考 ID? (这样“faq_item”模型/模式只需要几个字段,并且可以将引用 ID 分配给它所属的 Widget。

【问题讨论】:

    标签: ruby-on-rails schema


    【解决方案1】:

    如果每个小部件只有几个“常见问题解答项目”(或“详细信息”,我将引用它们)并且每个详细信息只不过是一个文本字符串,您可以将小部件的详细信息存储在序列化数组中比如:

    # models/widget.rb
    class Widget < ApplicationRecord
      # serialize the `details` attribute as JSON into 
      # the `details` column on the widgets table
      serialize :details, JSON
    end
    
    # db/schema.rb
    # ...
    create_table "widgets", force: :cascade do |t|
      t.string   "name"
      t.text     "details"
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    
    # rails console
    wid = Widget.create!(
    :name => 
    'Wideband, Voltage-Feedback Operational Amplifier With Disable',
    :details => [
    'Flexible supply range: 5-V to 12-V Single Supply, +/- 2.5-V to 5-V Dual Supply',                       
    'Unity-Gain Stable: 500 MHz (G = 1)',
    'High Output Current: 190 mA',
    'High Slew Rate: 1800 V/us',
    'Wideband 5-V Operation: 220 MHz (G = 2)'
    ])
    # => #<Widget ...>
    wid.details.first
    # => "Flexible supply range: 5-V to 12-V Single Supply, +/- 2.5-V to 5-V Dual Supply"
    

    您可以查看 Rails 5 serialization API 以了解有关 serialize 的更多信息。

    但是,如果您需要为每个详细信息(例如,created_at/updated_at 字段)存储更多信息,或者每个小部件具有多个详细信息,那么在您创建小部件详细信息的新表时可能是明智的。建议:

    # models/widget.rb
    class Widget < ApplicationRecord
      has_many :details, :dependent => :destroy
    end
    
    # models/widget/detail.rb
    class Widget::Detail < ApplicationRecord
      belongs_to :widget
    end
    
    # db/schema.rb
    # ...
    create_table "widget_details", force: :cascade do |t|
      t.integer  "widget_id"
      t.text     "content"
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    
    wid = Widget.create!(
    :name => 
    'CMOS, 125 MHz Complete DDS Synthesizer',
    :details => [
    Widget::Detail.create!(:content => '125 MHz Clock Rate'),
    Widget::Detail.create!(:content => 'On-Chip High Performance DAC'),
    Widget::Detail.create!(:content => '32-Bit Frequency Tuning Word')
    ])
    # => #<Widget ...>
    wid.details.first
    # => #<Widget::Detail ... content: "125 MHz Clock Rate" ...>
    

    【讨论】:

    • 似乎第二种可能性可能更有意义,因为每个“小部件”都可以有多个“细节”(有时是 10-15 个)。谢谢!
    【解决方案2】:

    如果您使用 Postgres,您可以在数据库中使用 JSONB 类型字段。使用 JSONB 数据类型,您将能够拥有非结构化数据,同时能够使用 Postgres 和 ActiveRecord 查询字段,而无需新表。

    像这样:

    rails g migration add_fields_to_widgets details:jsonb
    rails db:migrate
    

    在 Rails 控制台中测试您的小部件创建。

    Widget.create(name: "Widget Foo", details: { "how to use": "Instructions on how to use", "height": "12cm", "width": "100cm" })
    

    如果您想查找所有高度为 12 厘米的小部件,您只需进行如下查询:

    Widget.where("details->>'height' = ?", "12cm")
    

    这将返回您原来的 Widget Foo 对象,然后您就可以在前端使用纯 JavaScript 操作它。

    【讨论】:

    • pg in prod(这实际上只是为了学习),所以假装它是 sqlite/mysql ha。
    • 您可以使用 SQLite 的 json1 扩展,以采用类似的方法来管理 JSON 类型字段。就我个人而言,我发现在 Dev 和 Prod 环境中使用 pg 更容易。您可以在 Windows 中使用 pgAdmin 或在 macOS 中使用 Postgres.app 来安装它。如果它绝对需要是 SQLite,为了熟悉起见,我会选择答案 A。
    • 实际上,现在我想到了,您可以将 HTML 安全的 JSON 作为字符串存储在 SQLite 中。需要时,将其原始打印到 HTML 或 JS 文件中。您将无法像 JSONb 那样轻松地查询或操作,但如果它不是您软件核心的一部分,它可以工作。
    猜你喜欢
    • 1970-01-01
    • 2018-05-06
    • 2016-07-04
    • 2012-11-23
    • 2018-08-26
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多