假设我想允许管理用户通过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仅在启动时为每个模型执行一次.
development模式下运行时自动为你做的事情- 请参阅如何使用类重新加载类remove_const然后是load.)现在,已经说过,根据您需要解决的实际问题,您可能不需要动态地改变模式.而不是增加,比如列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
Run Code Online (Sandbox Code Playgroud)
你会用:
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
Run Code Online (Sandbox Code Playgroud)
上面的inject调用可以考虑到模型中,甚至可以考虑到可能需要额外的动态列/属性的所有模型继承的基类(请参阅关于如何使多个模型共享动态属性的相同表的多态关联dyn_attribs.)
UPDATE
通过常规HTML表单添加或重命名列.
假设您有一个DynAttrTable表示具有动态属性的表的模型,以及DynAttrDef定义给定表的动态属性名称.
跑:
script/generate scaffold_resource DynAttrTable name:string
script/generate scaffold_resource DynAttrDef name:string
rake db:migrate
Run Code Online (Sandbox Code Playgroud)
然后编辑生成的模型:
class DynAttrTable < ActiveRecord::Base
has_many :dyn_attr_defs
end
class DynAttrDef < ActiveRecord::Base
belongs_to :dyn_attr_table
end
Run Code Online (Sandbox Code Playgroud)
您可以继续编辑控制器和意见想在这个教程中,替换Recipe用DynAttrTable,并Ingredient用DynAttrDef.
或者,使用此处评论的其中一个插件,通过自动界面(包括所有铃声和口哨声)自动将表dyn_attr_tables和dyn_attr_defs表置于管理之下,代表您实现几乎零实施工作.
这应该让你去.