【问题标题】:mysql and rspec bugmysql 和 rspec 错误
【发布时间】:2013-12-20 04:00:13
【问题描述】:

在 Sequel Pro 中,使用以下语句创建了一个表:

CREATE TABLE dogs(
id INT PRIMARY KEY NOT NULL,
name TEXT,
color TEXT
);
*auto increment, under extra in structures, is checked so Sequel Pro generate primary keys automatically*

使用 mysql2,我在 ruby​​ 文件 classdog.rb 中编写了方法 insert,用于将新狗插入到表狗中。

classdog.rb 全文如下:

require 'mysql2'
require "debugger"

class Dog
  attr_accessor :name, :color, :id,

  @@db = Mysql2::Client.new(:host => '127.0.0.1', :username => 'root', :database => 'dogs')


  def initialize(name, color)
    @name = name
    @color = color
  end

  def self.db 
    @@db
  end

  def db 
    @@db
  end

  def insert 
    db.query("INSERT INTO dogs(name, color) VALUE('#{name}', '#{color}')")
  end
end

dog = Dog.new("simba", "grey") 
puts dog.insert

为了检查我的代码是否正常工作,我创建了这个 rspec 文件:

require "./classdog"

describe Dog do

  describe "#insert" do
    it "should insert a dog into the database" do
      dog = Dog.new("simba", "grey")
      sql_command = "SELECT * FROM dogs WHERE name = '#{dog.name}'";
      row_hash = {"id" => 1, "name" => "simba", "color" => "grey"}
      expect(Dog.db.query(sql_command).first).to eq(row_hash) 
    end
  end
end

当我使用以下命令在 ruby​​ 中运行我的规范文件时:

rspec spec_classdog.rb

我的测试通过了。

但有两件事我不明白:

  1. 当我使用 rspec 运行我的规范文件 spec_classdog.rb 时,表本身只会插入一条新狗。但是当我运行我的 ruby​​ 文件 classdog.rb 时,没有插入新的狗。

    • 为什么会这样?我预计运行我的 ruby​​ 文件可能会导致新的插入,而 rspec 只是为了检查以确保我的方法有效。这是因为我没有将参数名称和颜色传递给 insert 方法(意思是这样的:dog.insert("spot", "black")?
  2. 当我的 classdog.rb 文件中有以下代码时:

    dog = Dog.new("simba", "grey")
    puts dog.inspect
    puts dog.name
    puts dog.color
    puts dog.id
    

Ruby 提出:

请注意 dog.id 没有输出,如下所示:

    dog = Dog.new("simba", "grey") 
    puts dog.id

  • 为什么 ruby​​ 不显示 dog.id 中 dog 的 id?
  • 是因为在创建 TABLE dog 时将 id 设置为主键吗?
  • 添加一个名为 dog_id 的特定列会有帮助吗?

@PeterAlfvin:这是显示运行 puts dog.insert 的输出的图像

【问题讨论】:

  • 您在这里编写自己的 ORM 并犯了很多严重错误。 Proper escaping 不是可选的。为什么要走这条路而不是使用ActiveRecordSequelData Mapper?您不应该使用字符串插值来编写查询,这完全是鲁莽的。不建议直接针对 mysql2 库编写。
  • 如果您希望将此作为学术练习,那很好,但在编写查询时要格外小心。
  • @tadman:这纯粹是一个学术练习,但我仍然想知道在实践中是如何完成的(宁愿养成好习惯也不愿养成坏习惯)。将查找正确的转义和数据映射器;还没有学过 Rails,所以没有 ActiveRecord。如果您能就我的问题提供反馈,将不胜感激。谢谢!
  • 为什么您认为仅运行 classdog 时不会发生数据库插入?
  • 每次我简单地运行 classdog.rb 时,我都会刷新我的表,但我看不到任何变化。当我运行 rspec spec_classdog.rb 时,我刷新了我的表,我看到表中添加了一条新狗。

标签: mysql ruby rspec


【解决方案1】:

这至少是你的一些问题:

  • Mysql 不会为你自动创建主键列,除非你在列上指定auto_increment
  • insert 方法不提供id 值,因此它总是会失败,因为id 必须为非空值。
  • 鉴于上述情况,您的数据库中的任何条目都不是由您显示的代码创建的。

鉴于您已经解决了该问题,那么您将获得以下信息:

  • id 值仅由 mysql 在 数据库 中创建,而不是在 Ruby Dog 对象中创建,因此它在对象中始终为 nil,除非/直到您设置它(你目前没有这样做)。
  • 它与id 是主键无关
  • 创建dog_id 属性/列/字段不会对此产生影响
  • Ruby 揭示了dog.id 的价值;它的字符串表示恰好是空字符串

【讨论】:

  • 忘记添加 AUTO_INCREMENT 在 Sequel Pro 中已标记。
  • 好的。您应该更新您的问题,因为这非常重要。 ;-)
  • 嗨@Peter 会这样:def new_from_hash(hash) Dog.new(hash["name"], hash["color"]).tap {|dog| dog.id == hash["id"]} end: 注意在 Ruby Dog 对象中设置/创建 id 值?
  • 不,而且 SO cmets 并不是真正可接受的呈现代码以供审查的方式。我建议您在对您已经提出的答案感到满意时“关闭”这个 SO 问题,如果您想获得有关如何创建/维护 id 字段的反馈,请使用单独的问题。
  • 现在可以了。感谢您的所有反馈;真的很感激!
【解决方案2】:

运行spec spec_classdog.rb导致插入新狗的原因是因为我的rspec文件包含sql语句-因此运行rspec文件导致sql语句开始执行。

我的 rb 文件不包含任何 rspec 语句 - classdog.rb 只是为了告诉每个狗对象我希望它在 Ruby-land 中做什么。还要记住,在 Ruby 领域,狗对象在创建并执行其调用后会消失;它不会持续存在。因此需要数据库 - 解决了持久性问题。

请参阅 [此链接]:How to create/maintain ID field in Sequel Pro via Ruby and mysql2 以获取问题第二部分的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多