
Security News
Follow-up and Clarification on Recent Malicious Ruby Gems Campaign
A clarification on our recent research investigating 60 malicious Ruby gems.
A gem to help you retrofit UUIDs to your existing Rails application.
You have an existing Rails site that uses auto-incrementing ids, that you want to add, say, offline syncronization. The problem with auto-incrementing ids is that you will hit clashes if you create entries offline.
One solution is to use UUIDs, which has a very, very low probability of clashing. Now the problem is how do you add that to Rails? One way is to replace all the auto-incrementing ids with uuids, using something like activeuuid. This can be problematic if you have a running site, as converting all the ids and relationships would be a pain.
Enter: has_uuid
To use has_uuid you mirror all of the primary key id, and foreign key ids with another uuid column, and it makes sure you can search the whole object graph using uuids! If that didn't make sense check this out.
NOTE The name of the gem is rails_has_uuid because has_uuid was already taken.
Via Gemfile:
gem 'rails_has_uuid', require: 'has_uuid'
On the commandline
get install rails_has_uuid
###Migration
class SetupDatabase < ActiveRecord::Migration
def up
create_table :record_labels do |t|
t.string :name
t.uuid :uuid
end
create_table :albums do |t|
t.uuid :uuid
t.string :name
t.integer :record_label_id
t.uuid :record_label_uuid
t.integer :artist_id
t.uuid :artist_uuid
end
end
end
has_uuid adds a uuid type to mirations. On SQLite and MySQL it's a binary(16), on PostgreSQL it uses their native uuid type. Notice how we have both a record_label_id and record_label_uuid column...
###Model
class RecordLabel < ActiveRecord::Base
has_uuid
has_many :albums
end
class Album < ActiveRecord::Base
has_uuid
belongs_to :record_label
end
By calling the has_uuid class method, your model is primed.
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
# id: 1, the autogenerated uuid is: cf1ba930-6946-4bd5-9265-d9043e5dbb93
record_label = RecordLabel.create!(:name => 'Misfit Records')
# id: 2, the autogenerated uuid is: a957f2d6-371e-4275-9aec-b54a380688e0
RecordLabel.find(1, 2)
RecordLabel.find('cf1ba930-6946-4bd5-9265-d9043e5dbb93', a957f2d6-371e-4275-9aec-b54a380688e0)
RecordLabel.find(UUIDTools::UUID.parse('cf1ba930-6946-4bd5-9265-d9043e5dbb93'), UUIDTools::UUID.parse('a957f2d6-371e-4275-9aec-b54a380688e0'))
...will return an array of objects that match those ids
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist.record_label = record_label
artist.record_label_uuid
Will return the uuid of the associated record label.
The reverse is also true
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist.record_label_uuid = record_label.uuid
artist.record_label
Will return the record label object
Finally, it'll find the uuid when you associate via id i
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist.record_label_id = record_label.id
artist.record_label_uuid
Will be the uuid of the record label
Generally, a UUID will be a UUIDTools::UUID, but you can set uuids via a string, so these are equivalent:
uuid = UUIDTools::UUID.random_create
=> #<UUID:0x3fd4186240e0 UUID:7c9748da-f9fe-467e-bdb3-34ce2dc67605>
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords', :uuid => uuid)
artist_1 = Artist.create!(:name => 'NOFX')
artist.record_label_uuid = uuid.to
# is the same as
artist.record_label_uuid = '7c9748da-f9fe-467e-bdb3-34ce2dc67605'
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist_2 = Artist.create!(:name => 'Strung Out')
artist_3 = Artist.create!(:name => 'Screeching Weasel')
record_label.artists = [ artist_1, artist_2, artist_3 ]
record_label.save!
record_label.artists_uuids
Returns an array of UUIDTools::UUID objects that correspond to artist_1, artist_2, artist_3
it also works the other way:
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist_2 = Artist.create!(:name => 'Strung Out')
artist_3 = Artist.create!(:name => 'Screeching Weasel')
record_label.artist_uuids = [ artist_1.uuid, artist_2.uuid, artist_3.uuid ]
record_label.save!
record_label.artists
Returns artist_1, artist_2, artist_3
Finally, if you set a relationship id, it will automatically fetch the uuid for you
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
artist_1 = Artist.create!(:name => 'NOFX')
artist_2 = Artist.create!(:name => 'Strung Out')
artist_3 = Artist.create!(:name => 'Screeching Weasel')
record_label.artist_ids = [ artist_1.uuid, artist_2.uuid, artist_3.uuid ]
record_label.save!
record_label.artists_uuids
Will also return an array of UUIDTools::UUID objects that correspond to artist_1, artist_2, artist_3
All of these will return the same record
record_label = RecordLabel.create!(:name => 'Fat Wreck Chords')
# id: 1, the autogenerated uuid is: cf1ba930-6946-4bd5-9265-d9043e5dbb93
RecordLabel.find(1)
RecordLabel.find('cf1ba930-6946-4bd5-9265-d9043e5dbb93')
RecordLabel.find(UUIDTools::UUID.parse('cf1ba930-6946-4bd5-9265-d9043e5dbb93'))
Unfortunately, because of the way ARel works, you can only search via a UUIDTools::UUID
uuid = UUIDTools::UUID.random_create
=> #<UUID:0x3fd4186323c0 UUID:7cd2feb5-6929-4288-9ea4-c4e68927f289>
Artist.where('uuid = ?', uuid) # This works
Artist.where('uuid = ?', '7cd2feb5-6929-4288-9ea4-c4e68927f289') # This won't (except on PostgreSQL)
As a result, this also won't work
Artist.find_by_uuid('7cd2feb5-6929-4288-9ea4-c4e68927f289')
has_uuid uses the appraisal gem for testing against multiple versions of Rails.
To get started run:
appraisal install
Then to run tests against rails 3.2:
appraisal rails-3-2 rspec
Against rails 4.0
appraisal rails-4-0 rspec
Against rails 4.1
appraisal rails-4-1 rspec
Copyright (c) 2012 MadPilot Productions. See LICENSE.txt for further details.
FAQs
Unknown package
We found that rails_has_uuid demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A clarification on our recent research investigating 60 malicious Ruby gems.
Security News
ESLint now supports parallel linting with a new --concurrency flag, delivering major speed gains and closing a 10-year-old feature request.
Research
/Security News
A malicious Go module posing as an SSH brute forcer exfiltrates stolen credentials to a Telegram bot controlled by a Russian-speaking threat actor.