I've really been enjoying working with Lucky over the last few weeks, having developed on the web using only Rails for as long as I can remember. The community is fantastically welcoming and helpful, the Lucky framework is artfully crafted and intuitive, and it is fast without trying too hard or making things obscure.
Lucky has a CLI that can be used to generate apps using a very simple
lucky init command. If you generate an app with authentication built-in, you get a
User model with an ID column that's defaulted to an
Int64. Here's a (hopefully future-proof) set of steps to convert over to UUIDs in a scaffolded app!
pgcrypto extension to Postgres
The first action to take is straightforward, but requires a few steps.
We need to add the
pgcrypto extension to our database before the user model is created. To do that, we'll rename that migration and insert a new one before it:
mv 00000000000001_create_users.cr 00000000000002_create_users.cr
I also went ahead and manually created the migration for adding the extension:
Add this content to that file to create the extension in your database and remove it on rollback:
class EnablePgcrypto::V00000000000001 < Avram::Migrator::Migration::V1 def migrate execute "CREATE EXTENSION IF NOT EXISTS pgcrypto" end def rollback execute "DROP EXTENSION pgcrypto" end end
Tell Lucky to expect UUIDs by default for all model IDs
You can enable this on only specific modules, but if you're planning on using UUIDs for all of your application's records, go ahead and add this to
macro default_columns primary_key id : UUID timestamps end
You can read more about your options for this step in the Lucky Guides.
Change some types!
Crystal is a typed language, so we need to tell the compiler that everywhere it previously expected a 64-bit integer for a
User's ID, it now needs to expect a
UUID. We also need to change the code supplying that
User ID to supply a
UUID instead of an integer.
Rather than running through file-by-file, which may become out of date as the Lucky CLI and framework evolve, here are the two things to search for that you'll need to replace in your generated application:
The only occurrences of this type in your app should be for typing
User.id, and the switch to UUIDs is as simple as replacing
UUID. I'll provide my changes from the
PasswordResets::NewPage as an example.
class PasswordResets::NewPage < AuthLayout needs operation : ResetPassword needs user_id : Int64 ... end
class PasswordResets::NewPage < AuthLayout needs operation : ResetPassword needs user_id : UUID ... end
This is the last change we need to make. We've covered converting type expectations in the previous section, and now we'll convert the code that provides the
The change to make to callers of
to_i64 is to strip off
to_i64, and pass everything else to
UUID.new. I'll provide two examples below.
html NewPage, operation: operation, user_id: user_id.to_i64`
html NewPage, operation: operation, user_id: UUID.new(user_id)
To convert a generated Lucky app to use UUIDs, we completed these actions:
- Add the
pgcryptoextension to Postgres
- Tell Lucky to use UUIDs by default for model IDs
- Rename type delcarations from
- Refactor callers to pass
UUID.newvalues instead of
For further reading, head over to the Lucky Guides and search
UUID in the search bar at the top of the page!