ActiveRecord "find_unique_by"

38 views
Skip to first unread message

Bruno Facca

unread,
Jul 7, 2016, 11:14:03 AM7/7/16
to Ruby on Rails: Core
Hello,

I used MongoDB before PostreSQL with an ODM called MongoEngine, which has a method for retrieving single results from the DB. It is similar to ActiveRecord find_by! as it raises an exception if no matching records are found. The difference is, it also raises an exception if more than one record matched the query. I've been looking for a similar feature in ActiveRecord but haven't found any so far. 

I'm currently using the following workaround, which works with chained where methods,


def ensure_unique

 # Ensures an Active Record query returns a *single* record, or raise exception


 # Usage: MyModel.where(foo: 'bar').where(baz: 'qux).ensure_unique

 if self.many?

   raise ActiveRecord::RecordNotUnique, 'More than one record matched criteria. A single match was expected.'

 elsif self.empty?

   raise ActiveRecord::RecordNotFound, 'No matching records were found. A single match was expected.'

 else

   # The where method always returns a collection, even when only one record is found.

   # We want to return a single item.

   return self.first

 end

end


It could also be implemented as a query method (such as find_by!). However, I'd have to look further into it and find a way to support queries involving "AND" logic, such as chaining multiple where methods.

def find_unique_by!(*args)

 # Ensures an Active Record query returns a *single* record, or raise exception

 # Usage: MyModel.find_unique_by(foo: 'bar')

 result = where(*args)

 if result.many?

   raise ActiveRecord::RecordNotUnique, 'More than one record matched criteria. A single match was expected.'

 elsif result.empty?

   raise ActiveRecord::RecordNotFound, 'No matching records were found. A single match was expected.'

 else

   return result.first

 end

end


I'm wondering if the core team would approve the implementation of such feature. If positive, I would gladly write and commit it.

Best Regards,
Bruno Facca
Reply all
Reply to author
Forward
0 new messages