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

时间:2009-02-22 08:23:22

标签: ruby-on-rails

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

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

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/fc0b55fd4b2438a5

我过去曾使用Ruby来查询对象的可用方法。我似乎记得它非常慢。我太过绿了,Ruby和Rails知道一种优雅的方法来解决这个问题。我希望有人在这里。我也对这个问题完全不同,不涉及修改数据库。

6 个答案:

答案 0 :(得分:6)

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

但是,在运行时修改模式很复杂。

架构在首次加载时由每个模型类预加载(并从DB驱动程序缓存)。在production模式下,Rails仅在启动时为每个模型执行一次

  1. 为了在修改后强制Rails刷新缓存模式,你应该强制Ruby重新加载受影响模型的类(在development模式下运行时,Rails会在每次请求后自动为你做什么 - 见how to reload a class using remove_const followed by load。)
  2. 如果你有一个Mongrel集群,你还必须告知集群中的其他进程,这些进程在它们自己独立的内存空间中运行,还要重新加载它们的模型类(一些集群将允许你创建'restart.txt '文件,它将导致群集中所有进程的自动软重启,而无需代表您进行额外的工作。)
  3. 现在,已经说过,根据您需要解决的实际问题,您可能不需要动态地改变架构。您可以使用名为{{1的表格,而不是将列col1col2col3添加到某个表entries(模型Entry)中。 }},其中,条目dyn_attribshas_many :dyn_attribs都有dyn_attribs列(在这种情况下可以包含值keycol1或{{1 }}和col2列(列出col3value等的相应值。)

    因此,而不是:

    col1
    你会用:

    col2

    上述my_entry = Entry.find(123) col1 = my_entry.col1 #do something with col1 调用可以被分解到模型中,甚至可以分解为可能需要额外的动态列/属性的所有模型继承的基类(有关如何制作,请参阅Polymorphic associations有几个模型为动态属性共享相同的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 表。)


    <强>更新

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

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

    执行命令

    DynAttrTable

    然后编辑生成的模型:

    DynAttrDef

    您可以继续编辑控制器和视图like in this tutorial,将script/generate scaffold_resource DynAttrTable name:string script/generate scaffold_resource DynAttrDef name:string rake db:migrate 替换为class DynAttrTable < ActiveRecord::Base has_many :dyn_attr_defs end class DynAttrDef < ActiveRecord::Base belongs_to :dyn_attr_table end ,将Recipe替换为DynAttrTable

    或者,使用其中一个插件reviewed here自动将IngredientDynAttrDef表格置于自动界面管理之下(包括所有的铃声和口哨),几乎没有代表你的实施工作。

    这应该让你去。

答案 1 :(得分:3)

  

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

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

我覆盖模型的find和save方法,以便从admin_additions添加属性,并在更改时适当保存。模型表有一个大的文本字段,最初为空,我保存添加属性的非默认值。

本质上,视图和控制器可以假装模型的每个属性都有自己的列。这意味着form_for等所有工作。

答案 2 :(得分:2)

ActiveRecord :: Migration.add_column(用户,“电子邮件”,:字符串)

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:1)

如果您现在使用PostgreSQL执行此操作,您现在可能会使用JSON类型字段,然后只需将其存储在json哈希中。