# Find\_or\_create\_xxx behaving differently than create

**URL:** <https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677>\
**Category:** Rails\
**Created:** [May 16, 2010, 8:56am UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677 "2010-05-16T08:56:47Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![fearless\_fool](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/5e9695/32.png) [@fearless\_fool](https://www.ruby-forum.com/u/fearless_fool)\
**Post date:** [May 16, 2010, 8:56am UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677/1 "2010-05-16T08:56:47Z")

</div>

It appears that find\_or\_create\_by\_xxx is attempting type conversion  
where a simple create(…) does not. Bug?

Before going further, here’s the schema and the model:

create\_table “weather\_stations”, :force =\> true do |t|  
t.string “callsign”  
t.decimal “lat”, :precision =\> 9, :scale =\> 6  
t.decimal “lng”, :precision =\> 9, :scale =\> 6  
t.decimal “elevation\_m”, :precision =\> 5, :scale =\> 1  
end

class WeatherStation \< ActiveRecord::Base  
validates\_presence\_of :callsign, :lat, :lng  
validates\_uniqueness\_of :callsign, :case\_sensitive =\> false  
acts\_as\_mappable  
…  
end

[Note the “validates\_uniqueness\_of :callsign, :case\_sensitive =\> false”  
– that comes into play here.]

\*\* Assume ‘specs’ is a hash whose :callsign is a string:

> > specs  
> > =\> {:callsign=\>“0N6”, :lat=\>39.0128889, :lng=\>-75.5339722,  
> > :elevation\_m=\>15.0}
> 
> > specs[:callsign].class  
> > =\> String

\*\* The call to find\_or\_create\_by\_callsign fails – note that id comes  
back nil and the other fields are not filled in:

> > w = WeatherStation.find\_or\_create\_by\_callsign(specs[:callsign], :lat =\> specs[:lat], :lng =\> specs[:lng])  
> > =\> #\<WeatherStation id: nil, callsign: “0N6”, domain: nil, created\_at:  
> > nil, updated\_at: nil, lat: nil, lng: nil, elevation\_m: nil\>

\*\* The generated SQL shows a rollback:

WeatherStation Load (22.2ms) SELECT \* FROM `weather_stations` WHERE  
(`weather_stations`.`callsign` = ‘0N6’) LIMIT 1  
SQL (0.4ms) BEGIN  
WeatherStation Load (230.6ms) SELECT `weather_stations`.id FROM  
`weather_stations` WHERE (LOWER(`weather_stations`.`callsign`) = BINARY  
‘0n6’) LIMIT 1  
SQL (1.0ms) ROLLBACK

\*\* Using a simple .create() instead works:

> > x = WeatherStation.create(:callsign =\> specs[:callsign], :lat =\> specs[:lat], :lng =\> specs[:lng])  
> > =\> #\<WeatherStation id: 30774, callsign: “0N6”, domain: nil, created\_at:  
> > “2010-05-16 06:38:22”, updated\_at: “2010-05-16 06:38:22”, lat:  
> > #BigDecimal:8db79b0,‘0.390128889E2’,12(16), lng:  
> > #BigDecimal:8db7828,’-0.755339722E2’,12(16), elevation\_m: nil\>

\*\* …but looking at the SQL shows that it does the same check for  
uniqueness before inserting the row. Since the record isn’t in the  
table, it’s okay that it fails:

SQL (70.0ms) BEGIN  
WeatherStation Load (365.4ms) SELECT `weather_stations`.id FROM  
`weather_stations` WHERE (LOWER(`weather_stations`.`callsign`) = BINARY  
‘0n6’) LIMIT 1  
WeatherStation Create (2.0ms) INSERT INTO `weather_stations`  
(`callsign`, `domain`, `created_at`, `updated_at`, `lat`, `lng`,  
`elevation_m`) VALUES(‘0N6’, NULL, ‘2010-05-16 06:38:22’, ‘2010-05-16  
06:38:22’, 39.0128889, -75.5339722, NULL)  
SQL (3.3ms) COMMIT

I don’t understand enough about SQL’s “BINARY ‘0n6’” – is that the  
source of the trouble? Or is my validation bogus? Why is  
find\_or\_create\_by\_callsign() failing?

TIA.

- ff

---

<div class="post-metadata">

**Author:** ![fearless\_fool](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/5e9695/32.png) [@fearless\_fool](https://www.ruby-forum.com/u/fearless_fool)\
**Post date:** [May 16, 2010, 12:12pm UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677/2 "2010-05-16T12:12:20Z")

</div>

On May 16, 8:56 am, Fearless F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I don’t understand enough about SQL’s “BINARY ‘0n6’” – is that the  
> source of the trouble? Or is my validation bogus? Why is  
> find\_or\_create\_by\_callsign() failing?

I think it’s far more likely that it’s the nil attributes you noted  
that are the problem - they would certainly prevent the record from  
being saved.  
It appears that find\_or\_create\_by doesn’t quite work the way you  
expected it to - the code and unit tests suggests that you should be  
doing

WeatherStation.find\_or\_create\_by\_callsign(:callsign =\>  
specs[:callsign], :lat =\> specs[:lat], :lng =\> specs[:lng])

There is an another example in the docs of the usage you were  
attempting though, looks like it is just wrong/misleading.

Fred

---

<div class="post-metadata">

**Author:** ![fearless\_fool](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/5e9695/32.png) [@fearless\_fool](https://www.ruby-forum.com/u/fearless_fool)\
**Post date:** [May 16, 2010, 5:27pm UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677/3 "2010-05-16T17:27:52Z")

</div>

Frederick C. wrote:

> …  
> It appears that find\_or\_create\_by doesn’t quite work the way you  
> expected it to - the code and unit tests suggests that you should be  
> doing
> 
> WeatherStation.find\_or\_create\_by\_callsign(:callsign =\>  
> specs[:callsign], :lat =\> specs[:lat], :lng =\> specs[:lng])

You are correct – that works as expected.

> There is an another example in the docs of the usage you were  
> attempting though, looks like it is just wrong/misleading.

Correct again! The line in the doc is:

# No ‘Summer’ tag exists

Tag.find\_or\_create\_by\_name(“Summer”) # equal to Tag.create(:name =\>  
“Summer”)

which passes “Summer” rather than :name =\> “Summer”.

Sigh. A guy I used to work with told me that there is only one  
“authoritative documentation”, and that’s the source code itself.  
Evidently, Rails subscribes to this philosophy as well.

---

<div class="post-metadata">

**Author:** ![fearless\_fool](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/5e9695/32.png) [@fearless\_fool](https://www.ruby-forum.com/u/fearless_fool)\
**Post date:** [May 16, 2010, 5:59pm UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677/4 "2010-05-16T17:59:28Z")

</div>

On 16 May, 17:27, Fearless F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Frederick C. wrote:
> 
> > …

> > There is an another example in the docs of the usage you were  
> > attempting though, looks like it is just wrong/misleading.
> 
> Correct again! The line in the doc is:
> 
> # No ‘Summer’ tag exists
> 
> Tag.find\_or\_create\_by\_name(“Summer”) # equal to Tag.create(:name =\>  
> “Summer”)

Actually that usage is correct too. The misleading example is actuall  
demonstrating a different point.

> which passes “Summer” rather than :name =\> “Summer”.
> 
> Sigh. A guy I used to work with told me that there is only one  
> “authoritative documentation”, and that’s the source code itself.  
> Evidently, Rails subscribes to this philosophy as well.

A fair amount of effort has gone into the rails documentation of late.  
Like the rest of rails it only gets better if people contribute

---

<div class="post-metadata">

**Author:** ![fearless\_fool](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/5e9695/32.png) [@fearless\_fool](https://www.ruby-forum.com/u/fearless_fool)\
**Post date:** [May 16, 2010, 6:36pm UTC](https://www.ruby-forum.com/t/find-or-create-xxx-behaving-differently-than-create/188677/5 "2010-05-16T18:36:25Z")

</div>

Frederick C. wrote:

> A fair amount of effort has gone into the rails documentation of late.  
> Like the rest of rails it only gets better if people contribute

Agreed. But, as evidenced by my sometimes boneheaded questions in this  
forum, Rails would be in serious trouble if I were a contributor! 🙂  
(At least for now…)
