4

在我正在开发的 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

对我发送的项目对象的数据以及我正在创建的新元对象的所有检查都表明数据存在。但是当我meta.inspect在保存之前和之后进行保存时,它显示所有数据(除了 project_id)都处于默认状态(零)。我也检查过了meta.errors.nil?,果然,保存后没有任何错误。

最令人费解的是,如果我转身用那个 project_id 获取一个新的元实例并将数据放入,它不会为 db 保存任何问题。

这让我很沮丧,因为我在 Rails 和 Sinatra 中使用 ActiveRecord 构建了多个站点。这个问题完全让我困惑。谁能告诉我我做错了什么?

4

3 回答 3

6

下面是它的工作原理

  1. 首次访问模型时,会检索相应数据库表中的列并将其存储在模型数据中。可以通过:: columns类方法检索此信息。

  2. 当您访问某些模型的属性时,Ruby 不会在类中找到相应的方法并启动#method_missing 方法。该方法检查模型的 ::以检查相应的列是否存在。如果是这样,它将为该列创建一个访问器,以便下次访问该模型的属性时,将直接调用访问器方法,而无需调用#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”哈希。

注意:每列的数据都存储在模型实例内的特殊哈希实例中,而不是“@column_name”实例变量中。当您使用#attr_accessor 定义访问器时,您会阻止通过#method_missing 定义属性访问器的常用方法。您的数据存储在实例变量而不是“属性”哈希中,因此它不会保存到数据库中。

如果要向模型添加新属性,实际上需要向与该模型对应的数据库表添加列,然后重新加载整个应用程序。

于 2009-09-11T20:28:37.797 回答
1

数据库字段和临时 attr_accessor 声明的属性之间有一个重要的区别。如果你已经声明了你的列,那么 attr_accessor 声明是不必要的。

请记住,数据应该存储在模型的 attributes 属性中以便正确保存,而不是作为单个实例变量。

例如,要查看计划保存的内容:

class MyModel < ActiveRecord::Base
  attr_accessor :not_saved
end

model = MyModel.new(:not_saved => 'foo')

puts model.attributes.inspect

有一些方法可以获取有关模型中可用列的信息,例如:

MyModel.columns_names
于 2009-09-11T16:41:13.593 回答
0

attr_accessors 永远不会保存到数据库中。这些是实例中的内部变量。如果要保存值,则必须创建真实列。

进行迁移以声明列,然后重试。

于 2009-09-11T14:16:41.507 回答