This project is archived and is in readonly mode.
Add find :unique to ActiveRecord
Reported by Joris | July 30th, 2009 @ 03:46 PM
The current method of getting the result of a query is find
:fisrt.
This will essentially do a query with max 1 row.
However, sometimes a developer creates a query that doesn't work the way he thought it would.
My suggestion is to add a new find :unique
This should do the basically same as find :first, except that it
should not limit the number of records.
If more than 1 was found, it should raise an exception stating that
there are too many records (and also the number of records found,
just to inform the dev)
find :first should be deprecated for the use of getting a unique row from a query.
:first and :last have the same type of use. Finding the first or last in a list.
For example:
Person.find :unique, :conditions => { :ssid => ssid }
vs
Person.find :first, :conditions => { :ssid => ssid }
Also, the method_missing way of finding should use the unique.
Comments and changes to this ticket
-
Joris July 30th, 2009 @ 03:57 PM
So, I read the bar at the right :)
So, I didn't test this, I just typed it here, so I'm not sure if my manual diff is ok. anyway.. here's the code:In base.rb from activerecord:
in find(*args):
case args.first when :first then find_initial(options) when :all then find_every(options)
-
when :unique then find_unique(options)
add method:
def find_initial(options) options.update(:limit => 1) unless options[:include] find_every(options).first end
-
def find_unique(options)
-
records = find_every(options)
-
if records.size > 0 then
-
raise ActiveRecordError, "Too many records found: #{records.size}"
-
end
-
records.first
-
end
Also, some calls to find_initial should be replaced by find_unique, but I can imagine that would break some existing apps. So that might be for later.
-
-
Joris July 30th, 2009 @ 04:01 PM
So, I read the bar at the right :)
So, I didn't test this, I just typed it here, so I'm not sure if my manual diff is ok. anyway.. here's the code:In base.rb from activerecord:
in find(*args):
case args.first
when :first then find_initial(options) when :all then find_every(options)
-
when :unique then find_unique(options)</code>
add method:
def find_initial(options)
options.update(:limit => 1) unless options[:include] find_every(options).first end
-
def find_unique(options)
-
records = find_every(options)
-
if records.size > 0 then
-
raise ActiveRecordError, "Too many records found: #{records.size}"
-
end
-
records.first
-
end</code>
Also, some calls to find_initial should be replaced by find_unique, but I can imagine that would break some existing apps. So that might be for later. -
-
Pratik July 30th, 2009 @ 04:58 PM
Hey Joris,
I think you should discuss this change in the ML first. Also, your patch should have tests. Check http://guides.rubyonrails.org/contributing_to_rails.html for more details.
Thanks!
-
Pratik July 30th, 2009 @ 05:01 PM
- State changed from new to incomplete
-
MatthewRudy July 31st, 2009 @ 11:53 AM
is this really the proposed implementation?
def find_unique(options) records = find_every(options) if records.size > 0 then
raise ActiveRecordError, "Too many records found: #{records.size}"
end records.first end
I'd rather have the two db calls (count, and find_first)Also, I don't get the use-case.
Joris, do you have some examples of how you are using this feature?The only reason I've needed something similar is this case;
class SomeSortOfSettings < ActiveRecord::Base def self.instance self.first || self.new end end
namely a "Singleton" ActiveRecord,
but I think there's a better way to deal with this
(an ActiveRecord::Singleton class, perhaps)User.find(:unique, :conditions => {:username => "ralph"})
is silly,
you should just have a unique key on :username -
Joris July 31st, 2009 @ 12:00 PM
Having 2 queries would be a waste of db calls. If you expect 1 row, there's no need to do a count.
All queries for something with a unique index / natural key is where I'd do this. Just because it's contextual more correct, and it has no performance drawbacks except for a single check if there's another row in the resultset.
The implementation was just something I typed. I can imagine that there would be some other things that would need to happen, but basically that's how about what I had in mind.
Hibernate has a similar feature: query.uniqueResult
-
Pratik July 31st, 2009 @ 12:01 PM
- State changed from incomplete to wontfix
While I don't think this is gonna make it to the core, but the best implementation would probably be the one using :limit => 2.
This seem very project specific, hence you should just keep it in /lib or maybe make a plugin and see if many people find it useful or not. We can always reconsider the feature if more people are using it.
Thanks.
-
Ryan Bigg October 11th, 2010 @ 10:55 AM
- Tag cleared.
- Importance changed from to Low
Automatic cleanup of spam.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>