Ruby on rails 在Rails 2.2.2中动态地向ActiveRecord模型添加字段?

Ruby on rails 在Rails 2.2.2中动态地向ActiveRecord模型添加字段?,ruby-on-rails,Ruby On Rails,假设我希望允许管理用户通过Rails应用程序中的接口向ActiveRecord模型添加字段。我相信普通的ActiveRecord::迁移代码足以修改AR模型的表结构(我知道这对于许多应用程序来说是不明智的)。当然,理论上只能添加某些类型的字段 显然,向这个新修改的ActiveRecord模型添加(或编辑)记录的表单需要在运行时动态构建。一个通用的方法形式是不行的。这一讨论表明,这只能通过JavaScript实现 我过去曾使用Ruby来查询对象的可用方法。我似乎记得它慢得离谱。我对Ruby和Ra

假设我希望允许管理用户通过Rails应用程序中的接口向ActiveRecord模型添加字段。我相信普通的ActiveRecord::迁移代码足以修改AR模型的表结构(我知道这对于许多应用程序来说是不明智的)。当然,理论上只能添加某些类型的字段

显然,向这个新修改的ActiveRecord模型添加(或编辑)记录的表单需要在运行时动态构建。一个通用的方法形式是不行的。这一讨论表明,这只能通过JavaScript实现


我过去曾使用Ruby来查询对象的可用方法。我似乎记得它慢得离谱。我对Ruby和Rails太生疏了,不知道用什么优雅的方式来实现这一点。我希望这里有人可以。我也愿意使用完全不同的方法来解决这个问题,而不涉及修改数据库。

您可以使用这种方法,但是如果您希望能够通过这些新列进行搜索或排序,则必须编写(大量)自定义SQL。

我多次看到作为解决方案提供的表的动态更改/迁移,但我从未真正看到它的实现。这一解决方案很少实施的原因有很多

  • 如果该表很大,则该表可能会/将被锁定较长时间,而这段时间本应为启动时间
  • 为什么您的模型会动态变化?模型结构很少需要动态更改。这通常是一种迹象,表明您正试图以一种通用的方式对特定的事物进行建模
  • 这通常是一种试图产生“分类”模型的尝试,而不是用另一种方法更好地解决
  • 用于日常DML需求的同一用户通常不允许使用DDL语句。虽然这种情况可能会发生,而且通常在ROR领域,但这并不总是“正确”的方式

你想在这里实现什么?更好地理解这个问题可能会发现一个更自然的解决方案。

要访问当前为模型定义的列,请使用该方法-它将为您提供每个列的名称、类型和其他信息(例如它是否是主键等)

然而,在运行时修改模式是很微妙的

模式在第一次加载时由每个模型类预加载(并从DB驱动程序缓存)。在
production
模式下,Rails仅在启动前后对每个型号执行一次

  • 为了在修改后强制Rails刷新其缓存的模式,您应该强制Ruby重新加载受影响的模型的类(这与Rails在
    development
    模式下运行时在每次请求后自动为您执行的操作差不多-请参阅)
  • 如果您有一个Mongrel集群,您还必须通知集群中的其他进程(它们在各自独立的内存空间中运行)也重新加载其模型的类(某些群集将允许您创建“restart.txt”文件,这将导致群集中所有进程的自动软重启,而无需代表您执行其他工作。)
  • 现在,已经说过了,根据您需要解决的实际问题,您可能根本不需要动态更改模式。而不是将列
    col1
    col2
    col3
    添加到某些表
    条目
    (model
    Entry
    ),您可以使用一个名为
    dyn\u attribs
    的表,其中条目
    有许多:dyn\u attribs
    ,其中
    dyn\u attribs
    既有一个
    列(在这种情况下可以有值
    col1
    col2
    col3
    ),也有一个
    列(其中列出了
    col1
    col2
    等的相应值。)

    因此,不是:

    my_entry = Entry.find(123)
    col1 = my_entry.col1
    #do something with col1
    
    您可以使用:

    my_entry = Entry.find(123, :include => :dyn_attribs)
    dyn_attribs = my_entry.dyn_attribs.inject(HashWithIndifferentAccess.new) { |s,a|
      s[a.key] = a.value ; s
    }
    col1 = dyn_attribs[:col1]
    #do something with col1
    
    上述
    inject
    调用可以分解到模型中,甚至可以分解到所有模型继承的基类中,这些模型可能需要额外的动态列/属性(请参见如何使多个模型共享相同的
    dyn\u attribs
    动态属性表)


    更新

    通过常规HTML表单添加或重命名列

    假设您有一个表示具有动态属性的表的
    dynatrtable
    模型,以及一个定义给定表的动态属性名称的
    dynatrtef

    运行:

    然后编辑生成的模型:

    class DynAttrTable < ActiveRecord::Base
      has_many :dyn_attr_defs
    end
    
    class DynAttrDef < ActiveRecord::Base
      belongs_to :dyn_attr_table
    end
    
    class DynatTable
    您可以继续编辑控制器和视图,用
    dynatrtable
    替换
    Recipe
    ,用
    dynatrtref
    替换
    component

    或者,使用其中一个插件自动将
    dyn\u attr\u表
    dyn\u attr\u defs
    表置于一个自动化界面的管理之下(带有所有的铃铛和哨子),几乎不需要为您进行任何实施工作

    这会让你走的

    说我想允许 要向其添加字段的管理用户 通过接口的ActiveRecord模型 在Rails应用程序中

    以前我通过使用名为AdminAdditions的额外模型解决了这类问题。该表包括一个id、一个管理员用户id、一个模型名称字符串、一个类型字符串和一个默认值字符串

    我覆盖了模型的查找和保存方法,以从其管理添加中添加属性,并在更改时适当保存它们。模型表有一个大的文本字段,最初为空,我在其中保存添加属性的非默认值

    基本上,视图和控制器可以假装
    class DynAttrTable < ActiveRecord::Base
      has_many :dyn_attr_defs
    end
    
    class DynAttrDef < ActiveRecord::Base
      belongs_to :dyn_attr_table
    end