代码之家  ›  专栏  ›  技术社区  ›  localshred

创建ActiveRecord模型时出现问题:保存时缺少数据

  •  4
  • localshred  · 技术社区  · 15 年前

    在我开发的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 在保存之前和之后,它显示所有数据(除了项目ID)都处于默认状态(零)。我也查过了 meta.errors.nil? 当然,保存之后没有任何错误。

    最让人困惑的是,如果我回过头来,用那个项目的ID获取一个新的元实例,并将数据放入其中,它就不会给数据库带来任何问题。

    这让我很沮丧,因为我已经用ActiveRecord在Rails和Sinatra中建立了几个站点。这一问题使我完全困惑。有人能告诉我我做错了什么吗?

    3 回复  |  直到 15 年前
        1
  •  6
  •   Maxim Kulkin    15 年前

    这是它的工作原理

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

    2. 当您访问某个模型的属性时,Ruby在类中找不到相应的方法,并启动了method_missing method。该方法检查模型的: 检查相应的列是否存在。如果是这样,它会为该列创建一个访问器,以便下次访问该模型的属性时,可以直接调用访问器方法,而无需调用丢失的方法(后者较慢)。

    访问器如下所示:

    def my_attribute
      read_attribute(:my_attribute)
    end
    
    def my_attribute=(value)
      write_attribute(:my_attribute, value)
    end
    

    对于读取属性和写入属性方法,有一个快捷方式:# [] 和γ []= . 如果出于某种原因,您需要直接访问基础数据(例如,进行一些数据转换),您可以将其写短:

    def my_attribute
      self[:my_attribute]
    end
    
    def my_attribute=(value)
      self[:my_attribute] = value
    end
    

    模型有一个特殊的访问器--# attributes --它返回“column\u name=>value”哈希。

    注意:每列的数据存储在模型实例内的一个特殊哈希实例中,而不是“@column\u name”实例变量中。当您使用attr_访问器定义访问器时,您会阻止通过方法来定义属性访问器的常规方法。您的数据存储在实例变量中,而不是“ 属性 “散列,因此不会保存到数据库中。

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

        2
  •  1
  •   tadman    15 年前

    数据库字段和临时attr_访问器声明的属性之间有一个重要的区别。如果已经声明了列,则不需要attr访问器声明。

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

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

    class MyModel < ActiveRecord::Base
      attr_accessor :not_saved
    end
    
    model = MyModel.new(:not_saved => 'foo')
    
    puts model.attributes.inspect
    

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

    MyModel.columns_names
    
        3
  •  0
  •   François Beausoleil    15 年前

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

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