我在开发的 Sinatra 应用程序中使用 ActiveRecord 在数据库中创建新模型行时遇到问题。正在创建有问题的对象,没有任何错误(使用保存!,没有引发异常),但我为保存指定的大部分数据都不存在。
class ProjectMeta < ActiveRecord::Base
attr_accessor :completion_ratio, :num_stories, :num_completed_stories, :original_target_date, :current_target_date
...
def self.create_from_project(project)
meta = ProjectMeta.new
meta.project_id = project.id
meta.num_stories = project.num_stories
meta.num_completed_stories = project.num_completed_stories
meta.completion_ratio = ProjectMeta.calculate_ratio(project.num_completed_stories, project.num_stories)
meta.current_target_date = project.current_target_date
meta.save!
meta
end
...
end
对来 self 正在发送的项目对象以及我正在创建的新元对象的数据的所有检查都表明数据存在。但是当我在保存前后执行 meta.inspect
时,它显示所有数据(project_id 除外)都处于默认状态(零)。我还检查了 meta.errors.nil?
果然,保存后没有任何错误。
最令人费解的是,如果我回过头来获取一个具有该 project_id 的新元实例并将数据放入其中,那么它不会对数据库造成任何问题。
这让我很沮丧,因为我已经使用 ActiveRecord 在 Rails 和 Sinatra 中构建了多个站点。这一个问题完全让我困惑。谁能告诉我我做错了什么?
最佳答案
这是它的工作原理
首次访问模型时,会检索相应数据库表中的列并将其存储在模型数据中。可以通过::columns 检索此信息。类方法。
当您访问某些模型的属性时,Ruby 在类中找不到相应的方法并启动#method_missing 方法。该方法检查模型的::columns检查相应的列是否存在。如果是这样,它会为该列创建一个访问器,以便下次访问该模型的属性时,将直接调用访问器方法,而无需调用 #method_missing(后者速度较慢)。
访问器看起来像这样:
def my_attribute
read_attribute(:my_attribute)
end
def my_attribute=(value)
write_attribute(:my_attribute, value)
end
#read_attribute 和#write_attribute 方法有一个快捷方式:# []和#[]= .如果出于某种原因您需要直接访问底层数据(例如,进行一些数据转换),您可以将它们写得简短:
def my_attribute
self[:my_attribute]
end
def my_attribute=(value)
self[:my_attribute] = value
end
模型有一个特殊的访问器 -- # attributes -- 返回一个“column_name => value”散列。
注意:每列的数据都存储在模型实例中的特殊 Hash 实例中,而不是“@column_name”实例变量中。当您使用#attr_accessor 定义访问器时,您会阻止通过#method_missing 定义属性访问器的常用方法。您的数据存储在实例变量中而不是“attributes”散列中,因此它不会保存到数据库中。
如果要向模型添加新属性,实际上需要向数据库表中添加与该模型对应的列,然后重新加载整个应用程序。
关于ruby - 创建 ActiveRecord 模型时出现问题 : data missing from save,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1406560/