Ruby on Rails 和 NoSQL,添加字段
我刚刚开始研究 Mongodb 和 MongoID with Rails,我发现它很棒。 NoSQL 的帮助之一是,我可以随时向模型中添加额外的字段,而无需任何额外的工作:
class Page
include Mongoid::Document
include Mongoid::MultiParameterAttributes
field :title, :type => String
field :body, :type => String
field :excerpt, :type => String #Added later
field :location, :type => String #Added later
field :published_at, :type => Time
validates :title, :presence => true
validates :body, :presence => true
validates :excerpt, :presence => true
end
而且这可以完美地发挥作用。但我的问题是,(抱歉,如果这是微不足道的)现有条目是空白的,并且没有为新添加的字段定义值。例如,在示例博客应用程序中,在我发布了两篇文章后,我决定将摘录和位置字段添加到我的数据库中(请参阅上面的代码)。添加这些新字段后发布的任何博客文章都可以确保为摘录字段填写了值。但是在添加这两个新字段之前发布的帖子具有空值(这是可以理解的原因),我无法验证。有一个优雅的解决方案吗?
谢谢。
I'm just diving into Mongodb and MongoID with Rails and I find it awesome. One thing the NoSQL helps is when I can add extra fields to my model without any extra effort whenever I want:
class Page
include Mongoid::Document
include Mongoid::MultiParameterAttributes
field :title, :type => String
field :body, :type => String
field :excerpt, :type => String #Added later
field :location, :type => String #Added later
field :published_at, :type => Time
validates :title, :presence => true
validates :body, :presence => true
validates :excerpt, :presence => true
end
And this works perfectly as it should. But my question is, (sorry if this is trivial) the existing entries are blank and have no defined value for the newly added field. For example, in a sample blog application, after I've published two posts, I decide to add an excerpt and a location field to my database (refer code above). Any blog post that is published after the addition of these new fields can be made sure to have a value filled in for the excerpt field. But the posts published prior to the addition of these two new fields have null values (which is understandable why) which I cannot validate. Is there an elegant solution for this?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
共有三个基本选项:
after_initialize
挂钩将默认摘录添加到现有对象中。(1) 当您进行更改时需要(可能很大)时间,但这只是一次性的事情,之后您不必担心。您可以从 MongoDB 中提取每个页面,执行
page.excerpt = 'some default excerpt'
,然后将其保存回 MongoDB。如果您有很多页面,您会希望一次处理 100 个页面。如果这样做,您将能够搜索摘录,而不必担心应该如何处理null
。您还可以通过将 JavaScript 片段发送到 MongoDB 来在 MongoDB 中执行此操作:(2) 会像这样:
您可以如果您不介意使用 lambda,请将
unless self.excerpt
移至:unless
:这应该非常快速且易于设置,但也有缺点。首先,您的 MongoDB 中可能有一堆
null
,您可能需要在搜索期间对其进行特殊处理。此外,您将携带一堆代码和逻辑来处理旧数据,但随着时间的推移,这些包袱的使用会越来越少。此外,after_initialize
调用并不是免费的。(3) 要求您跳过验证非新页面摘录是否存在(
:unless => :new_record?
),否则您必须找到某种方法来区分新对象和旧对象同时还正确处理新旧页面的编辑。您还可以强迫人们在更改页面时提供摘录并保留原样的验证;包括:default =>; ''
在您的field :excerpt
上将处理视图等中的任何nil
问题。如果可能的话我会选择(1)。如果更新需要太长时间,并且您希望在修复 MongoDB 时启动并运行站点,您可以添加
:default =>; ''
在更新时删除:default
选项,重新启动,并手动修补任何通过的杂散。There are three basic options:
after_initialize
hook to add a default excerpt to existing objects when you pull them out of MongoDB.(1) requires a (possible large) time hit when you make the change but it is just a one time thing and you don't have to worry about it after that. You'd pull every Page out of MongoDB, do
page.excerpt = 'some default excerpt'
, and then save it back to MongoDB. If you have a lot of Pages you'll want to process them in chunks of, say, 100 at a time. If you do this, you'll be able to search on the excerpt without worrying about what you should do withnull
s. You can also do this inside MongoDB by sending a JavaScript fragment into MongoDB:(2) would go something like this:
You could move the
unless self.excerpt
up to the:unless
if you didn't mind using a lambda:This should be pretty quick and easy to set up but there are downsides. First of all, you'd have a bunch of
null
s in your MongoDB that you might have to treat specially during searches. Also, you'd be carrying around a bunch of code and logic to deal with old data but this baggage will be used less and less over time. Furthermore, theafter_initialize
calls do not come for free.(3) requires you to skip validating the presence of the excerpt for non-new Pages (
:unless => :new_record?
) or you'd have to find some way to differentiate new objects from old ones while also properly handling edits of both new and old Pages. You could also force people to supply an excerpt when they change a Page and leave your validation as-is; including a:default => ''
on yourfield :excerpt
would take care of anynil
issues in views and such.I'd go with (1) if possible. If the update would take too long and you wanted the site up and running while you were fixing up MongoDB, you could add a
:default => ''
while updating and then remove the:default
option, restart, and manually patch up any strays that got through.