假设我想允许管理用户通过Rails应用程序中的界面向ActiveRecord模型添加字段.我相信正常的ActiveRecord :: Migration代码足以修改AR模型的表结构(对于许多应用程序来说这是不明智的 - 我知道).当然,理论上只能添加某些类型的字段.
显然,需要在运行时动态构建向这个新修改的ActiveRecord模型添加(或编辑)记录的表单.一种常见的form_for方法是行不通的.这个讨论表明这只能通过JavaScript实现.
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/fc0b55fd4b2438a5
我过去曾使用Ruby来查询对象的可用方法.我似乎记得它非常慢.我太过绿了,Ruby和Rails知道一种优雅的方法来解决这个问题.我希望有人在这里.我也对这个问题完全不同的方法持开放态度,不涉及修改数据库.
要访问当前为模型定义的列,请使用columns方法 - 它将为每列提供其名称,类型和其他信息(例如它是否为主键等)
但是,在运行时修改模式很精细.
首次加载时,每个模型类都预先加载(并从DB驱动程序缓存)模式.在production
模式下,Rails仅在启动时为每个模型执行一次.
为了在修改后强制Rails刷新缓存模式,你应该强制Ruby重新加载受影响模型的类(Rails在每次请求之后,在development
模式下运行时自动为你做的事情- 请参阅如何使用类重新加载类remove_const
然后是load
.)
如果你有一个Mongrel集群,你还必须告知集群中的其他进程,这些进程在它们自己独立的内存空间中运行,还要重新加载它们的模型类(一些集群将允许你创建一个'restart.txt'文件,这将导致群集中所有进程的自动软重启,而无需代表您进行额外的工作.)
现在,已经说过,根据您需要解决的实际问题,您可能不需要动态地改变模式.而不是增加,比如列col1
,col2
并col3
于某些表entries
(型号Entry
),您可以使用一个名为表dyn_attribs
,其中入境has_many :dyn_attribs
,并在dyn_attribs
既有key
的列(在这种情况下可以有值col1
,col2
或col3
)和value
列(其中列出了相应的值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_attribs
.)
UPDATE
通过常规HTML表单添加或重命名列.
假设您有一个DynAttrTable
表示具有动态属性的表的模型,以及DynAttrDef
定义给定表的动态属性名称.
跑:
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
,并Ingredient
用DynAttrDef
.
或者,使用此处评论的其中一个插件,通过自动界面(包括所有铃声和口哨声)自动将表dyn_attr_tables
和dyn_attr_defs
表置于管理之下,代表您实现几乎零实施工作.
这应该让你去.