新手问题 通过 Hash 的方式无法创建记录

aijinsong · 2015年05月04日 · 最后由 aijinsong 回复于 2015年05月06日 · 2309 次阅读
@accountTemp = Hash.new
@accountTemp['name'] = 'aijinsong'
@accountTemp['email'] = '[email protected]'
@accountTemp['password'] = 'aiajsajs'
@accountTemp['password_confirmation'] = 'aiajsajs'
Account.create(@accountTemp)

上面这段代码执行后会有如下日志,导致无法创建新的账号:

DEBUG -  Account Exists (0.6ms)  SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1
DEBUG -   (0.1ms)  ROLLBACK

但是:

account = Account.create(:email => '[email protected]', :name => 'aijinsong', :password => 'aiajsajs', :password_confirmation => 'aiajsajs', :role => "admin")

这段代码执行后是成功的。日志如下:

DEBUG -   (0.1ms)  BEGIN
DEBUG -  Account Exists (0.3ms)  SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1
DEBUG -  SQL (0.2ms)  INSERT INTO `accounts` (`blogs_count`, `comments_count`, `created_at`, `crypted_password`, `email`, `logo`, `name`, `profile_image_url`, `profile_url`, `provider`, `role`, `uid`) VALUES (0, 0, '2015-05-04 21:52:14', '$2a$10$7FoH64NjksN39nKI7gm7zu/36dlbgxWYpdn5590JWxjhlJersyN6W', '[email protected]', NULL, 'aijinsong', NULL, NULL, NULL, 'admin', NULL)
DEBUG -   (0.5ms)  COMMIT

AR 对象创建失败,是会给出原因的,你的第一个例子稍微改一下,然后看看错误原因是什么?

account = Account.create(@accountTemp)
puts accourt.errors

#1 楼 @lgn21st 非常感谢。已解决,详细描述如下。在这里抛出另外一个问题:

DEBUG -  Account Exists (1.0ms)  SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1

如上是一条 DEBUG 信息。第一次学习使用 ruby 和 ActiveRecord,提示信息给到的反馈,让我误以为是数据已存在。所以希望能够弄清楚 ActiveRecord 给到这个 DEBUG 信息是何解?

以下为根据提示调整后的日志和代码。

  DEBUG -    RELOAD (0.3626s) /Users/aijinsong/Documents/projects/opensource/robbin_site/app/controllers/room.rb
  DEBUG -   (0.9ms)  BEGIN
  DEBUG -  Account Exists (1.0ms)  SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1
  DEBUG -   (0.5ms)  ROLLBACK
{:role=>["是无效的"]}

修改了代码,增加了对 role 的赋值就对了。

@accountTemp = Hash.new
    @accountTemp['name'] = 'aijinsong'
    @accountTemp['email'] = '[email protected]'
    @accountTemp['password'] = 'aiajsajs'
    @accountTemp['password_confirmation'] = 'aiajsajs'
    @accountTemp['role'] = 'admin'
    temp = Account.create(@accountTemp)
DEBUG -  Account Exists (1.0ms)  SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1

这条记录可以理解为在 AR 对象创建前,先根据在 AR 中定义的 uniqueness validate 做一次 Account Exists 检察。检查是通过 Select … 查找 email 是不是已经存在,不存在的时候才会继续保存数据,检查和保存会用一个 BEGIN … COMMIT 事务语句包裹起来,如果检查到 email 已经存在或者 role 不存在的时候,用 ROLLBACK 回滚当前事务内的所有数据库变化。

#3 楼 @lgn21st 这么理解下来,我觉得逻辑好像有些问题。 逻辑疑问一:是否应该先 insert 之后,才能够查询到数据呢? 逻辑疑问二:如果校验结果如日志所述,那么应该已经存在了邮箱,此时应该 rollback 的不是?

#4 楼 @aijinsong

  1. 为什么应该在 insert 之后再检查?
  2. rollback 不区分 update, select 或者 insert, 而是取消当前 从 begin … rollback 之间所有的操作。

#5 楼 @lgn21st 非常感谢您的耐心回复讨论。

  1. 当然不是(应该 insert 之后做检查)。我的意思是 insert 后才应该能够查询出数据。如 [email protected] 在当时的数据库中是不存在的,但是为何有如下日志且出现 Account Exists。 ruby DEBUG - (0.1ms) BEGIN DEBUG - Account Exists (0.3ms) SELECT 1 AS one FROM `accounts` WHERE LOWER(`accounts`.`email`) = LOWER('[email protected]') LIMIT 1 DEBUG - SQL (0.2ms) INSERT INTO `accounts` (`blogs_count`, `comments_count`, `created_at`, `crypted_password`, `email`, `logo`, `name`, `profile_image_url`, `profile_url`, `provider`, `role`, `uid`) VALUES (0, 0, '2015-05-04 21:52:14', '$2a$10$7FoH64NjksN39nKI7gm7zu/36dlbgxWYpdn5590JWxjhlJersyN6W', '[email protected]', NULL, 'aijinsong', NULL, NULL, NULL, 'admin', NULL) DEBUG - (0.5ms) COMMIT
  2. 同上日志描述 Account Exists,如果已经存在,为何下面还能插入成功。最后既然操作成功,说明肯定是我对 ActiveRecord 的处理过程还不是很理解,所以希望理解清楚。 这些日志的确对我去分析该问题产生影响,还请指教。

你可检查数据库,看有没有重复就清楚了。 那个 debug 应该不是说重复了,只是说在检查重复。

#7 楼 @chenge 已明确,当时不存在这条数据。如果如你所述,这个逻辑就是通的。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号