从ActiveRecord / Rails查询中检索单个记录

时间:2014-03-25 08:43:49

标签: ruby-on-rails activerecord ruby-on-rails-4 rails-activerecord

我发出如下所示的查询,完全检索0或1条记录:

car = Car.where(vin: '1234567890abcdefg')

返回的内容当然是长度为1的汽车列表。所以我最终在查询结尾处添加了.first

car = Car.where(vin: '1234567890abcdefg').first

似乎在Rails中应该有更好的方法。是否存在类似.onlyOne的内容,只返回一个Car并在超过1时抛出异常?

car = Car.where(vin: '1234567890abcdefg').onlyOne

car = Car.onlyOne(vin: '1234567890abcdefg')

5 个答案:

答案 0 :(得分:1)

car = Car.find_by_vin('1234567890abcdefg')

答案 1 :(得分:1)

Rails 4

你想要find_by(vin: 123),你可以传递find_by任何字段/值名称的哈希来查找。

例如

Car.find_by(vin: '123')

如果没有找到带有该vin的汽车,或者与该vin值匹配的单辆汽车,则返回nil。如果你添加一个爆炸(即find_by!),如果没有找到带有该vin的汽车,它将引发异常。

如果您想在发现多个错误时引发错误,那么您必须自己编写。如果您不应该遇到多辆汽车具有相同vin的情况,最好的方法是使用Car模型进行唯一性验证,例如

class Car < ActiveRecord::Base
  validates_uniqueness_of :vin # or validates :vin, unique: true
end

Rails 3

您想要find_by_vin(并且可以使用您的任何属性的名称替换vin

例如

Car.find_by_vin('123')

如果找不到带有该vin的汽车,或者具有该vin值的单辆汽车,则返回nil。如果你添加一个爆炸(即find_by_vin!),如果没有找到带有该vin的汽车,它将引发异常。

有关详细信息:http://guides.rubyonrails.org/active_record_querying.html#retrieving-objects-from-the-database

答案 2 :(得分:1)

我认为没有任何东西可以抛出一个例外,但是在rails 4中只有一个:

car = Car.find_by(vin: '1234567890abcdefg') 

将返回唯一的一个。强制唯一性的最佳方法是在模型/数据库级别上执行:

class Car < ActiveRecord::Base
  validates :vin, uniqueness: true
end

如果由于某种原因,你确实需要在有多辆汽车的情况下抛出异常,你可以在模型上编写一个方法(或猴子补丁活动记录):

class Car < ActiveRecord::Base
  class << self

    def only_one!(options)
       list = where(options)
       raise "Exactly one car isn't available" if list.size > 1 or list.size == 0
       list.first
    end

  end
end

或使用问题:

#lib/active_record_only_one.rb:
module ActiveRecordOnlyOne
  extend ActiveSupport::Concern

  module ClassMethods
    def only_one!(options)
      list = where(options)
      raise "Exactly one isn't available" if list.size > 1 or list.size == 0
      list.first
    end
  end
end

ActiveRecord::Base.send(:include, ActiveRecordOnlyOne)

#config/initializers/only_one.rb
require "active_record_only_one"

然后致电:

Car.only_one!(vuid: "1234567890abcdefg")

答案 3 :(得分:0)

您可以使用taketake!

car = Car.where(vin: '1234567890abcdefg').take

如果没有与给定字符串匹配的记录,则返回 nil

car = Car.where(vin: '1234567890abcdefg').take!

如果没有与给定字符串

匹配的记录,则返回ActiveRecord::RecordNotFound

来自Guides(1.1.2,1.1.5 and 1.1.6)

car = Car.take  is equivalent to

SELECT * FROM cars LIMIT 1

答案 4 :(得分:0)

Rails 6.1 为此引入了 find_sole_by(或 where(...).sole)。

似乎完全符合要求:

<块引用>

查找唯一匹配的记录。如果未找到记录,则引发 ActiveRecord::RecordNotFound。如果找到多条记录,则引发 ActiveRecord::SoleRecordExceeded

用例很简单:

Car.find_sole_by(vin: '1234567890abcdefg')