用于ROR的find_by的替代方案

时间:2013-09-05 17:32:22

标签: ruby-on-rails

我正在研究迈克尔·哈特尔的导轨教程,在6.3上,需要替代user_spec模型的代码。他的代码是:

let(:found_user) { User.find_by(email: @user.email) }

看起来我可以在哪里使用,但不确定正确的语法。我尝试了以下几种变体:

let(:found_user) { User.where(:email => "@user.email")}

我确信这是一个非常简单的答案,但不能得到它。

2 个答案:

答案 0 :(得分:4)

let(:found_user){User.where(email: @user.email).first}

let(:found_user){User.find_by_email(@user.email)}

第一个使用where的用户返回一个与where子句匹配的用户集合,这就是为什么你需要.first的原因(它直到你抓取记录时才执行sql)类似于.all.first.each)。

我想说这不是在单元测试中执行数据库命令的最佳实践。你在具体测试什么?您是否有理由需要将用户保存在数据库中,而不能只执行以下操作:

let(:user){User.new(email: 'some email')}

答案 1 :(得分:1)

ActiveRecord::Base#find_by实际上是where(options).first,但这是一个你不需要做的额外通话。

Rails还提供了mildly deprecated“magic”find_by_<attribute>[and_<attribute>]方法,这些方法使用method_missing来解析基于方法名称的含义。虽然框架确实提供了这些,但我提醒不要使用它们,因为它们必然比“本机”方法慢,并且更能抵抗重构。

我建议坚持使用find_by作为一般情况,并尝试避免在规范和测试中使用数据库。

factory_girl gem提供了一种创建类的存根版本的方法,它通过回答true persisted?并提供id来嘲笑数据库返回的记录。 }。

或者,您可以在不保存的情况下构建新记录:User.new(attribute: value, ...)并对其进行测试:

it "does some things" do
  user = User.new(attributes)

  # make user do some things

  expect(things).to have_happened
end