## Upgrading from 1.3.0 to 1.4.0
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=1.3.0&to=1.4.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.4.0`
- Avram should be `~> 1.4.0`
- Authentic should be `~> 1.0.2`
- LuckyEnv should be `~> 0.3.0`
- LuckySecTester should be `~> 0.3.3`
- Run `shards update`
- Upgrade Lucky CLI on Windows (Scoop)
```
scoop bucket add lucky https://github.com/luckyframework/scoop-bucket
scoop install lucky
```
### General updates
- Update: your BaseSerializer and remove inheritance then add `include Lucky::Serializable`. [See PR](https://github.com/luckyframework/lucky/pull/1947)
- Remove: all setup bash scripts in favor of Crystal versions. [See PR](https://github.com/luckyframework/lucky_cli/pull/875)
- Remove: any local variable, or argument passed to a method that has a `?` for Crystal 1.16 compatibility. [See PR](https://github.com/luckyframework/avram/pull/1083)
- Update: any call to `where_*` join methods in favor of `join_*` join methods. [See PR](https://github.com/luckyframework/avram/pull/1090)
```crystal
# Update this
UserQuery.new.where_subscriptions(SubscriptionQuery.new)
# to this
UserQuery.new.join_subscriptions(SubscriptionQuery.new)
```
### Optional update
- Update: to Crystal 1.16 or later and use type-safe ENV methods. [See PR](https://github.com/luckyframework/lucky_env/pull/39)
```crystal
LuckyEnv.init_env(".env")
LuckyEnv.load(".env")
ENV["DEV_PORT"] #=> "3000"
LuckyEnv.dev_port #=> 3000
```
## Upgrading from 1.2.0 to 1.3.0
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=1.2.0&to=1.3.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.3.0`
- Avram should be `~> 1.3.0`
- Authentic should be `~> 1.0.1`
- Carbon should be `~> 0.6.0`
- Carbon Adapter should be `~> 0.6.0`
- Run `shards update`
- Upgrade Lucky CLI on Windows (Scoop)
```
scoop bucket add lucky https://github.com/luckyframework/scoop-bucket
scoop install lucky
```
### General updates
No required updates needed for this release.
### Optional update
- Update: to Crystal 1.14
- Update: All previously pre-compiled tasks should now show in your `./bin/` as Crystal files. Build these to run them as compiled.
```
crystal build --release bin/lucky.gen.secret_key.cr -o bin/lucky.gen.secret_key
crystal build --release bin/lucky.watch.cr -o bin/lucky.watch
crystal build --release bin/lucky.exec.cr -o bin/lucky.exec
# ... etc...
```
## Upgrading from 1.1.0 to 1.2.0
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=1.1.0&to=1.2.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.2.0`
- Avram should be `~> 1.2.0`
- Carbon should be `~> 0.5.1`
- Carbon Adapter should be `~> 0.5.0`
- LuckyFlow should be `~> 0.10.0`
- Run `shards update`
- Upgrade Lucky CLI on Windows (Scoop)
```
scoop bucket add lucky https://github.com/luckyframework/scoop-bucket
scoop install lucky
```
### General updates
- Add: the annotation `@[DB::Field(ignore: true)]` to any instance variables you've added to your models. [See PR](https://github.com/luckyframework/avram/pull/996)
- Remove: the Nexploit NPM package from your Github Actions if you're using SecTester. [See PR](https://github.com/luckyframework/lucky_sec_tester/pull/34)
### Optional update
- Replace: any use of `Avram::Nothing.new` with `IGNORE`. [See PR](https://github.com/luckyframework/avram/pull/1018)
## Upgrading from 1.0.0 to 1.1.0
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=1.0.0&to=1.1.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.1.0`
- Avram should be `~> 1.1.0`
- Authentic should be `~> 1.0.0`
- Carbon should be `~> 0.4.0`
- LuckyTask should be `~> 0.3.0`
- LuckyFlow should be `~> 0.9.2`
- LuckySecTester should be `~> 0.3.2`
- Run `shards update`
### General updates
- Add: `Avram.initialize_logging` to your `config/log.cr` file near the bottom. [See PR](https://github.com/luckyframework/avram/pull/967)
- Update: all LuckyTask tasks. [See PR](https://github.com/luckyframework/lucky_task/pull/25)
```crystal
# All help_message instance methods are macro calls
def help_message
"my help message"
end
# is now
help_message "my help message"
# Calls to `name`, `summary`, or `help_message` from your task `call` method are now classes.
def call
# `name` is now
self.class.task_name
# `summary` is now
self.class.task_summary
# `help_message` is now
self.class.task_help_message
end
```
### Optional update
- Add: `allow_blank: true` on String columns you want to allow empty strings to be saved. [See PR](https://github.com/luckyframework/avram/pull/956)
```crystal
class Post < BaseModel
table do
column title : String
# Field is required, but storing "" is ok
column sub_title : String, allow_blank: true
end
end
```
## Upgrading from 1.0.0-rc1 to 1.0.0
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=1.0.0-rc1&to=1.0.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.0.0`
- Avram should be `~> 1.0.0`
- Authentic should be `~> 1.0.0`
- Run `shards update`
### General updates
- Update: to at least Crystal 1.6 or later.
- Update: Any use of a `DeleteOperation` that assumed the record could be nil should now assume the record will always exist in the block. [See PR for more details](https://github.com/luckyframework/avram/pull/887)
### Optional update
## Upgrading from 0.30 to 1.0.0-rc1
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.30.0&to=1.0.0-rc1).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 1.0.0-rc1`
- Avram should be `~> 1.0.0-rc1`
- Authentic should be `~> 0.9.0`
- Carbon (and carbon_sendgrid_adapter) should be `~> 0.3.0`
- LuckyFlow should be `~> 0.9.0`
- Run `shards update`
### General updates
- Add: Avram to your `shard.yml` as a dependency.
- Add: `require "avram/lucky"` to `src/shards.cr` right below `require "lucky"`. [See PR](https://github.com/luckyframework/avram/pull/772)
- Add: `require "avram/lucky/tasks"` to `tasks.cr` right below `require "lucky/tasks/**"`. [See PR](https://github.com/luckyframework/lucky_cli/pull/764)
- Update: to Crystal 1.4 or later.
- Add: `include Lucky::RedirectableTurbolinksSupport` in your `BrowserAction` if you are using turbolinks.
- Add: `live_reload_connect_tag` to your `src/components/shared/layout_head.cr` and `reload_port: 3001` to your `config/watch.yml` file for live browser reloading. [See this PR](https://github.com/luckyframework/lucky_cli/pull/767) and [this PR](https://github.com/luckyframework/lucky/pull/1693)
- Update: `Avram::Params.new()` now takes `Hash(String, Array(String))` instead of `Hash(String, String)`. [See PR](https://github.com/luckyframework/avram/pull/847)
- Update: arg names in `validate_numeric` from `less_than` and `greater_than` to `at_least` and `no_more_than`. [See PR](https://github.com/luckyframework/avram/pull/867)
- Update: your LuckyFlow configuration...
```crystal
# spec/spec_helper.cr
# ...
require "spec"
# ...
require "lucky_flow"
require "lucky_flow/ext/lucky"
require "lucky_flow/ext/avram"
# ...
# spec/setup/configure_lucky_flow.cr
# ...
LuckyFlow::Spec.setup
```
### Optional updates
- Update the `lucky_sec_tester` shard to version `0.1.0`
- Replace turbolinks with [Turbo](https://turbo.hotwired.dev/)
- Replace laravel-mix with [Vite](https://vitejs.dev/)
## Upgrading from 0.29 to 0.30
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.29.0&to=0.30.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 0.30.0`
- Authentic should be `~> 0.8.2`
- LuckyFlow should be `~> 0.7.3` *NOTE*: 0.8.0 is released, but may not be compatible yet
- Run `shards update`
### General updates
- Update: `spec/support/api_client.cr` with `app AppServer.new` defined in the class.
```crystal
class ApiClient < Lucky::BaseHTTPClient
app AppServer.new
def initialize
super
headers("Content-Type": "application/json")
end
def self.auth(user : User)
new.headers("Authorization": UserToken.generate(user))
end
end
```
- Update: the `request.remote_ip` method now pulls from the last (instead of first) valid IP in the `X-Forwarded-For` list. [See PR for details](https://github.com/luckyframework/lucky/pull/1675)
- Update: All primary repo branches are now `main`. Adjust any references accordingly.
- Update: `./script/system_check` and remove mentions of `ensure_process_runner_installed`. Nox is built-in [See PR for details](https://github.com/luckyframework/lucky_cli/pull/720)
### Optional updates
- Update: uses of `AvramSlugify` to `Avram::Slugify`. [See PR for details](https://github.com/luckyframework/avram/pull/786)
- Update: specs to use transactions instead of truncate. [See PR for details](https://github.com/luckyframework/avram/pull/780)
```crystal
# in spec/spec_helper.cr
require "./setup/**"
# Add this line
Avram::SpecHelper.use_transactional_specs(AppDatabase)
include Carbon::Expectations
include Lucky::RequestExpectations
include LuckyFlow::Expectations
```
- Remove: the `spec/setup/clean_database.cr` file. This accompanies the transactional specs update
- Update: the `spec/setup/start_app_server.cr` file. This file is no longer needed if your action specs make standard calls, and are not using LuckyFlow. [See PR for details](https://github.com/luckyframework/lucky/pull/1644)
## Upgrading from 0.28 to 0.29
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.28.2&to=0.29.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `">= 1.0.0"`
- Lucky should be `~> 0.29.0`
- Authentic should be `~> 0.8.1`
- Caron SendgidAdapter should be `~> 0.2.0` if you're using SendGrid
- LuckyEnv should be `~> 0.1.4`
- LuckyTask should be `~> 0.1.1`
- JWT should be `~> 1.6.0`
- Run `shards update`
### General updates
- Remove: any usage of the `lucky build.release` task. Use `shards build --release --production` instead. [See PR for details](https://github.com/luckyframework/lucky/pull/1612)
- Update: to Crystal version 1.0.0 or greater. Versions below 1.0 are no longer supported. [See PR for details](https://github.com/luckyframework/lucky/pull/1618)
- Update: your `AppServer` in `src/app_server.cr` to have a `listen` method defined. This method is now abstract on `Lucky::BaseAppServer`. [See PR for details](https://github.com/luckyframework/lucky/pull/1622)
- Update: if you use UUID for primary keys in your models, ensure you've added the "pgcrypto" extension to your DB. The `id` value will no longer be generated on the Crystal side. [See PR for details](https://github.com/luckyframework/avram/pull/725)
- Update: any usage of the `Status` enums in your SaveOperations to be `OperationStatus`. [See PR for details](https://github.com/luckyframework/avram/pull/759)
- Remove: any usage of `route` or `nested_route` from your actions, and replace them with the actual route. (Optionally, you can use the [Legacy Routing Shard](https://github.com/matthewmcgarvey/lucky_legacy_routing)) [See PR for details](https://github.com/luckyframework/lucky/pull/1597)
- Update: your `src/app.cr`, and move the requires for `config/server` and `config/**` to the top of the require stack. [See PR for details](https://github.com/luckyframework/lucky_cli/pull/676)
- Update: your `package.json` (Full Apps only) to use `yarn run mix` instead of just `mix`. [See PR for details](https://github.com/luckyframework/lucky_cli/pull/682)
- Update: your `src/app_server.cr` middleware stack with `Lucky::RequestIdHandler.new` at the top of the stack before `Lucky::ForceSSLHandler.new`. [See PR for details](https://github.com/luckyframework/lucky_cli/pull/700)
- Update: any usage of `add_belongs_to` with namespaced models to specify the `references` option. [See PR for details](https://github.com/luckyframework/avram/pull/742)
- Update: the `error_html` method in `src/actions/errors/show.cr`. Replace the following code
```diff
- html Errors::ShowPage, message: message, status: status
+ html_with_status Errors::ShowPage, status, message: message, status_code: status
```
- Rename: the `status` variable to `status_code` in `src/pages/errors/show_page.cr`
### Optional updates
- Add: a new config `Lucky::RequestIdHandler` in `config/server.cr` to set a request ID.
```crystal
#...
Lucky::RequestIdHandler.configure do |settings|
settings.set_request_id = ->(context : HTTP::Server::Context) {
UUID.random.to_s
}
end
```
- Add: query cache to `config/database.cr`. [See PR for details](https://github.com/luckyframework/avram/pull/763)
```crystal
Avram.configure do |settings|
settings.database_to_migrate = AppDatabase
# In production, allow lazy loading (N+1).
# In development and test, raise an error if you forget to preload associations
settings.lazy_load_enabled = LuckyEnv.production?
# Disable query cache during tests
settings.query_cache_enabled = !LuckyEnv.test?
end
```
## Upgrading from 0.27 to 0.28
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.27.2&to=0.28.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `">= 1.0.0"`
- Lucky should be `~> 0.28.0`
- Authentic should be `~> 0.8.0`
- Carbon should be `~> 0.2.0`
- Caron SendgidAdapter should be `~> 0.1.0` if you're using SendGrid
- Dotenv should be replaced with [LuckyEnv ~> 0.1.3](https://github.com/luckyframework/lucky_env)
- Run `shards update`
### General updates
- Remove: `needs context : HTTP::Server::Context` from any component, as well as passing it in to the `mount()` for the components. [See PR for details](https://github.com/luckyframework/lucky/pull/1488)
- Rename: all `DeleteOperation.destroy` calls to `DeleteOperation.delete`
- Update: `avram_enum` to use the Crystal `enum`. [See PR for details](https://github.com/luckyframework/avram/pull/698)
```diff
# Models get this update
- avram_enum State do
+ enum State
Started
Ended
end
# Factories get this update
- state Thing::State.new(:started)
+ state Thing::State::Started
# Operations get this update
- SaveThing.create(state: Thing::State.new(:started)) do |op, t|
+ SaveThing.create(state: Thing::State::Started) do |op, t|
# Queries get this update
- ThingQuery.new.state(Thing::State.new(:started).value)
+ ThingQuery.new.state(Thing::State::Started)
```
- Update: your `config/env.cr` to this.
```crystal
# Environments are managed using `LuckyEnv`. By default, development, production
# and test are supported.
# If you need additional environment support, add it here
# LuckyEnv.add_env :staging
```
- Update: any use of `Lucky::Env` to use `LuckyEnv`. (e.g. `Lucky::Env.test?` -> `LuckyEnv.test?`). [See PR for details](https://github.com/luckyframework/lucky_cli/pull/655)
- Update: any use of `Lucky::Env.name` to use `LuckyEnv.environment`.
- Update: any use of `route` or `nested_route`, and replace them with the generated routes. Use `lucky routes` to view all generated routes. If you still need this, you can use the [Lucky Legacy Routing](https://github.com/matthewmcgarvey/lucky_legacy_routing) shard.
- Add: the [luckyframework/carbon_sendgrid_adapter](https://github.com/luckyframework/carbon_sendgrid_adapter) shard if you're using Sendgrid to send mail. Be sure to `require "carbon_sendgrid_adapter"` in `config/email.cr`.
### Optional updates
- Update: all routes to use underscore (`_`) instead of dash (`-`) as word separator. Include the `Lucky::EnforceUnderscoredRoute` module in your base actions. (e.g. `/this-route` -> `/this_route`)
```crystal
class BrowserAction < Lucky::Action
include Lucky::EnforceUnderscoredRoute
# ...
end
```
- Update: `send_text_response()` responses if you're passing a raw JSON string to use `raw_json()` instead.
- Add: `include Lucky::SecureHeaders::DisableFLoC` to your `BrowserAction` to disable FLoC.
```crystal
class BrowserAction < Lucky::Action
include Lucky::SecureHeaders::DisableFLoC
# ...
end
```
- Remove: `normalize-scss` from your `package.json` and replace with `modern-normalize` if you're using `normalize-scss`.
- Update: any query where you write code like `if SomeQuery.new.first?` to `if SomeQuery.new.any?`. `.any?` returns a Bool instead of loading the whole object which has a small performance gain.
- Add: the [Breeze](https://github.com/luckyframework/breeze) shard to your development workflow!
## Upgrading from 0.26 to 0.27
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.26.0&to=0.27.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `">= 0.36.1, < 2.0.0"`
- Lucky should be `~> 0.27.0`
- Authentic should be `~> 0.7.3`
- Carbon should be `~> 0.1.4`
- Dotenv should be `~> 1.0.0` or replace with [LuckyEnv 0.1.0](https://github.com/luckyframework/lucky_env)
- LuckyFlow should be `~> 0.7.3`
- JWT (if you use Auth) should be `~> 1.5.1`
- LuckyTask needs to be added as a dependency
```
lucky_task:
github: luckyframework/lucky_task
version: ~> 0.1.0
```
- Run `shards update`
### General updates
- Add: the new `lucky_task` shard as a dependency.
- Update: your `tasks.cr` file with the new require, and module name change:
```crystal
# tasks.cr
ENV["LUCKY_TASK"] = "true"
# Load Lucky and the app (actions, models, etc.)
require "./src/app"
require "lucky_task"
require "./tasks/**"
require "./db/migrations/**"
require "lucky/tasks/**"
LuckyTask::Runner.run
```
- Update: all tasks in your `tasks/` directory to inherit from `LuckyTask::Task` instead of `LuckyCli::Task`. (e.g. `Db::Seed::RequiredData < LuckyCli::Task` -> `Db::Seed::RequiredData < LuckyTask::Task`)
- Update: your `config/cookies.cr` with a default cookie path of `"/"`.
```crystal
Lucky::CookieJar.configure do |settings|
settings.on_set = ->(cookie : HTTP::Cookie) {
# ... other defaults
# Add this line. See ref: https://github.com/crystal-lang/crystal/pull/10491
cookie.path("/")
}
end
```
### Optional updates
- Update: to Crystal 1.0.0. You can continue to use Crystal 0.36.1 if you need.
- Update: `LuckyFlow` to be a `development_dependency`.
## Upgrading from 0.25 to 0.26
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.25.0&to=0.26.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.36.1`
- Lucky should be `~> 0.26.0`
- Authentic should be `~> 0.7.2`
- LuckyFlow should be `~> 0.7.2`
- Run `shards update`
### General updates
- Update: your `Procfile` web to point to `./bin/YOUR APP NAME` instead of `./app`. NOTE: this is dependant on how you deploy your app, so only required if you use the heroku_buildpack for Lucky. [read more](https://github.com/luckyframework/lucky_cli/pull/601) and [more](https://github.com/luckyframework/heroku-buildpack-crystal/pull/11)
- Update: any references directly to an `Avram::Attribute(T)` generic. e.g. `Avram::Attribute(String?)` -> `Avram::Attribute(String)`. [read more](https://github.com/luckyframework/avram/pull/586)
- Update: any custom database types to include the class method `adapter` that returns the `Lucky` constant. [read more](https://github.com/luckyframework/avram/pull/587)
- Update: any custom database types to include the class method `criteria(query : T, column) forall T`. [read more](https://github.com/luckyframework/avram/pull/591)
- Remove: any call to `after_completed` in a SaveOperation. The `after_save` and `after_commit` now run even if no change is updated. [read more](https://github.com/luckyframework/avram/pull/612)
- Rename: all `Avram::Box` classes, filenames, and the `spec/support/boxes` directory (sorry 😬) to `Avram::Factory`, etc.... e.g. `UserBox` -> `UserFactory` [read more](https://github.com/luckyframework/avram/pull/614). [view discussion](https://github.com/luckyframework/lucky/discussions/1282)
- Notice: the `Avram::Operation` now avoids calling `run` if there were validation errors in any `before_run`. This may change some of your logic, or create surprised. [read more](https://github.com/luckyframework/avram/pull/621)
### Optional updates
- Update: any calls made in Github CI config to `lucky db.create_required_seeds` to `lucky db.seed.required_data`. [read more](https://github.com/luckyframework/lucky_cli/pull/600)
- Update: any use of `route` or `nested_route` in your actions to explicitly specify the route. This isn't deprecated, yet, but will be in a future version and eventually removed.
- Add: `DB::Log.level = :info` to your `config/log.cr` file to quiet the excessive "Executing query" notices
- Update: your Laravel Mix to version 6. [read more](https://github.com/luckyframework/lucky_cli/pull/592)
- Add: a new migration to have UUID primary keys generated from the database for existing tables. [read more](https://github.com/luckyframework/avram/pull/578)
```crystal
# in a new migration file
def migrate
enable_extension "pgcrypto"
execute("ALTER TABLE products ALTER COLUMN id SET DEFAULT gen_random_uuid();")
execute("ALTER TABLE users ALTER COLUMN id SET DEFAULT gen_random_uuid();")
end
```
- Remove: all calls to `flash.keep` in your actions. [read more](https://github.com/luckyframework/lucky/pull/1374)
## Upgrading from 0.24 to 0.25
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.24.0&to=0.25.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.35.1`
- Lucky should be `~> 0.25.0`
- Authentic should be `~> 0.7.1`
- LuckyFlow should be `~> 0.7.1`
- Run `shards update`
### General updates
- Update: all `Avram::Operation` to implement the new interface.
- Your main instance method should be called `run`
- The `run` method should return just the value you need. No more `yield self, thing` / `yield self, nil`.
- Call the operation with `MyOperation.run(params)` instead of `MyOperation.new(params).submit`
- The `MyOperation.run` class method takes a block that yields the operation, and your return value. Similar to `SaveOperation`.
```crystal
# Before Update
class RequestPasswordReset < Avram::Operation
#...
def submit
if valid?
yield self, user
else
yield self, nil
end
end
end
# Use in your Action
RequestPasswordReset.new(params).submit do |operation, user|
end
# After Update
class RequestPasswordReset < Avram::Operation
#...
def run
if valid?
user
else
nil
end
end
end
# Use in your Action
RequestPasswordReset.run(params) do |operation, user|
end
```
- Rename: all usage of `with_defaults` to `tag_defaults`
- Update: query objects to no longer rely on mutating the query.
```crystal
# Before update
q = UserQuery.new
q.age.gte(21)
q.to_sql #=> SELECT * FROM users WHERE age >= 21
# After update
q = UserQuery.new
q.age.gte(21)
q.to_sql #=> SELECT * FROM users
```
- Rename: all usage of `raw_where` to `where`
- Update: query objects that set a default query in the initializer to use the `defaults` method.
```crystal
# Before update
class UserQuery < User::BaseQuery
def initialize
admin(false)
end
end
UserQuery.new.to_sql #=> SELECT * FROM users WHERE admin = false
# After update
class UserQuery < User::BaseQuery
def initialize
defaults &.admin(false)
end
end
UserQuery.new.to_sql #=> SELECT * FROM users WHERE admin = false
```
- Update: any `has_many through` model association to include the new assocation chain.
```crystal
# Before update
has_many posts : Post
has_many comments : Comment, through: :posts
# After update
# The first in the array is the association you're going through
# The second is that through's association.
has_many posts : Post
has_many comments : Comment, through: [:posts, :comments]
```
- Update: any query that used a `where_XXX` on a `belongs_to` from the pluralized name to singularized.
```crystal
# assuming Post belongs_to User
# Before update
PostQuery.new.where_users(UserQuery.new)
# After update
PostQuery.new.where_user(UserQuery.new) # Notice the 'where_user' is single now
```
### Optional updates
- Update: any mention of `DB_URL` that we told you to use should actually be `DATABASE_URL`
- Remove: any include for `include Lucky::Memoizable`. This is now included in `Object` and available everywhere
- Update: HTML tags that display a `UUID` no longer need to cast to String. `link uuid, to: Whatever`
- Remove: any `start_server` or `start_server.dwarf` files in the top-level directory. These are now built to your `bin/`
- Update: `config/email.cr` to include a case for development to print emails.
```crystal
# config/email.cr
BaseEmail.configure do |settings|
if Lucky::Env.production?
# ...
elsif Lucky::Env.development?
settings.adapter = Carbon::DevAdapter.new(print_emails: true)
else
# ...
end
end
```
- Update: any `call(io : IO)` method in your tasks, and use the `output` property instead for testing. [read more](https://github.com/luckyframework/lucky_cli/pull/557)
- Update: your `package.json` with all the latest front-end updates. [read more](https://github.com/luckyframework/lucky_cli/pull/553)
- Rename: your seed tasks `tasks/create_required_seeds.cr` -> `tasks/db/seed/required_data.cr`, and `tasks/create_sample_seeds.cr` -> `tasks/db/seed/sample_data.cr`
- Update: `config/log.cr` to silence some of the query logging with `DB::Log.level = :info`.
## Upgrading from 0.23 to 0.24
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.23.0&to=0.24.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.35.1`
- Lucky should be `~> 0.24.0`
- Authentic should be `~> 0.7.0`
- Run `shards update`
### General updates
- Rename: all instances of the `m` method to `mount`. e.g. `m Shared::Footer, year: 2020` -> `mount Shared::Footer, year: 2020`.
- Update: `config/database.cr` with new `Avram::Credentials`.
```crystal
AppDatabase.configure do |settings|
if Lucky::Env.production?
settings.credentials = Avram::Credentials.parse(ENV["DATABASE_URL"])
else
settings.credentials = Avram::Credentials.parse?(ENV["DATABASE_URL"]?) || Avram::Credentials.new(
database: database_name,
hostname: ENV["DB_HOST"]? || "localhost",
# NOTE: This was changed from `String` to `Int32`
port: ENV["DB_PORT"]?.try(&.to_i) || 5432,
username: ENV["DB_USERNAME"]? || "postgres",
password: ENV["DB_PASSWORD"]? || "postgres"
)
end
end
```
- Rename: all instances of `AppClient` to `ApiClient` in your `spec/` directory.
- Update: `script/setup` with `shards install --ignore-crystal-version`. Alternatively, you can set a global `SHARDS_OPTS=--ignore-crystal-version` environment variable
### Optional updates
- Update: `redirect_back` with `allow_external: true` argument if you need to allow external referers
- Update: your database credentials with the new `query` option to pass query string options
```crystal
# config/database.cr
settings.credentials = Avram::Credentials.new(
database: database_name,
hostname: ENV["DB_HOST"]? || "localhost",
port: ENV["DB_PORT"]?.try(&.to_i) || 5432,
username: ENV["DB_USERNAME"]? || "postgres",
password: ENV["DB_PASSWORD"]? || "postgres",
# This option is new
query: "initial_pool_size=5&max_pool_size=20"
)
```
- Add: `disable_cookies` to `ApiAction` in `src/actions/api_action.cr`.
## Upgrading from 0.22 to 0.23
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.22.0&to=0.23.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.35.0`
- Lucky should be `~> 0.23.0`
- Authentic should be `~> 0.6.1`
- LuckyFlow should be `~> 0.7.0`
- jwt should be `~> 1.4.2`
- Run `shards update`
### General updates
- Update: `params.get` now strips white space. If you need the raw value, use `params.get_raw`.
- Rename: `mount` to `m` in all pages that use components. **Note: This was reverted in the next version**
- Update: all mounted components to use new signature `mount(MyComponent.new(x: 1, y: 2))` -> `m(MyComponent, x: 1, y:2)`.
- Remove: `Lucky::SessionHandler` and `Lucky::FlashHandler` from `src/app_server.cr`
### Optional updates
- Add: `Avram::RecordNotFoundError` to the `dont_report` array in `src/actions/errors/show.cr`
- Update: `def render(error : Lucky::RouteNotFoundError` to `def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError)` in `src/actions/errors/show.cr`.
- Update: any CLI tasks that use `ARGV` to use the native args [See implementation](https://github.com/luckyframework/lucky_cli/pull/466)
## Upgrading from 0.21 to 0.22
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.21.0&to=0.22.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.35.0`
- Lucky should be `~> 0.22.0`
- Authentic should be `~> 0.6.0`
- jwt should be `~> 1.4.2`
- Run `shards update`
## Upgrading from 0.20 to 0.21
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.20.0&to=0.21.0).
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.34.0`
- Lucky should be `~> 0.21.0`
- Authentic should be `~> 0.5.4`
- LuckyFlow should be `~> 0.6.3`
- Run `shards update`
### General updates
- Rename: `config/logger.cr` to `config/log.cr`
- Update: `config/log.cr` to use the new `Log`. [See implementation](https://github.com/luckyframework/lucky_cli/blob/v0.21.0/src/web_app_skeleton/config/log.cr#L1)
- Update: `Procfile.dev` and update the `system_check` to `script/system_check && sleep 100000`.
- Update: all `Lucky.logger.{level}("message")` calls to use the new Crystal Log `Log.{level} { "message" }`
- Remove: the following lines from `config/database.cr`
```crystal
# Uncomment the next line to log all SQL queries
# settings.query_log_level = ::Logger::Severity::DEBUG
```
### Updating `Lucky.logger`
Before this version, you would log data like this:
```crystal
Lucky.logger.debug("Logging some message")
Lucky.logger.info({path: @context.request.path})
```
Now, you would write this like:
```crystal
# Use the Crystal std-lib log for simple String messages
Log.debug { "Logging some message" }
# Use the Dexter extension for logging key/value data
Log.dexter.info { {path: @context.request.path} }
```
## Upgrading from 0.19 to 0.20
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.19.0&to=0.20.0).
- Update `.crystal-version` file to `0.34.0`
- Upgrade to crystal 0.34.0
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.34.0
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.34.0`
- Lucky should be `~> 0.20.0`
- Authentic should be `~> 0.5.2`
- LuckyFlow should be `~> 0.6.2`
- Run `shards update`
### General updates
- Update: `link` no longer accepts a `String` path or URL, it must be an Action. Change `link()` to an `a` tag with an `href` (`a "Google", href: "https://google.com"`), or use an action class with `link` (`link "Home", to: "/" ` becomes `link("Home", to: Home::Index)`.
- Remove: the `?` from any `needs` using a predicate method. e.g. `needs signed_in? : Bool` -> `needs signed_in : Bool`. Lucky now automatically creates a method ending with `?` for `needs` with a `Bool` type.
- Update: your development `ENV["PORT"]` to be `ENV["DEV_PORT"]` if you need to customize the port your local server is running on.
- Update: all `SaveOperation` classes where a raw hash is being passed in. e.g. `MyOperation.new({"name" => "Gary"})` -> `MyOperation.new(name: "Gary")`, or if you must use a hash, wrap it in params first: `MyOperation.new(Avram::Params.new({"name" => "Gary"})`
- Remove: the `on:` option from `needs` inside every Operation class. e.g. `needs created_by : String, on: :create` -> `needs created_by : String`. You will need to explicitly pass these when calling `new`, `create`, and `update`.
### Optional updates
- Update: all instance variables called from a `needs` on a page or component can now just use the method of that name. e.g. `@current_user` -> `current_user`
- Add: `include Lucky::CatchUnpermittedAttribute` to the `class Shared::Field(T)` in `src/components/shared/field.cr`. This will raise a nicer error if you forget to permit a column in your SaveOperation
- Add: the new `Lucky::RemoteIpHandler.new` to your app handlers in `src/app_server.cr` just before `Lucky::RouteHandler.new`.
- Add: `robots.txt` to your `public/` directory.
```
User-agent: *
Disallow:
```
- Update: `UserSerializer` to inherit from the `BaseSerializer` if it doesn't already.
- Add: `cookie.http_only(true)` to your `config/cookies.cr` file. This goes inside your `settings.on_set` block.
- Update: your node dependencies where needed
- Update: the `setup` script in `script/setup`. [See implementation](https://github.com/luckyframework/lucky_cli/tree/ee7699bddde50b80e495a89edb442b754f627239/src/web_app_skeleton/script/setup.ecr). Be sure to remove the ECR tags.
- Add: this line `system_check: script/system_check && $SHELL` to your `Procfile.dev`
- Add: the new `system_check` script in `script/system_check`. Note: you may need to `chmod +x script/system_check`. [See implementation](https://github.com/luckyframework/lucky_cli/tree/ee7699bddde50b80e495a89edb442b754f627239/src/web_app_skeleton/script/system_check.ecr). Be sure to remove the ECR tags.
- Add: the new `function_helpers` script in `script/helpers/function_helpers`. [See implementation](https://github.com/luckyframework/lucky_cli/tree/ee7699bddde50b80e495a89edb442b754f627239/src/web_app_skeleton/script/helpers/function_helpers)
- Add: the new `text_helpers` script in `script/helpers/text_helpers`. [See implementation](https://github.com/luckyframework/lucky_cli/tree/ee7699bddde50b80e495a89edb442b754f627239/src/web_app_skeleton/script/helpers/text_helpers)
## Upgrading from 0.18 to 0.19
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.18.0&to=0.19.0).
- Update `.crystal-version` file to `0.33.0`
- Upgrade to crystal 0.33.0
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.33.0
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Crystal should be `0.33.0`
- Lucky should be `~> 0.19.0`
- Authentic should be `~> 0.5.1`
- LuckyFlow should be `~> 0.6.2`
- Run `shards update`
### Recommended (but optional) changes
#### GZip static assets
* [Add the compression plugin](https://github.com/luckyframework/lucky_cli/commit/8bc002ab51cb13e67f515c4de977766f96825a18#diff-73db280623fcd1a64ac1ab76c8700dbc) to `package.json`
* Make [these changes](https://github.com/luckyframework/lucky_cli/commit/8bc002ab51cb13e67f515c4de977766f96825a18#diff-cd19e42e70bfbcf2a12480b0b6b1f590)
to your `webpack.mix.js` file
* In `src/app_server.cr` add `Lucky::StaticCompressionHandler.new("./public", file_ext: "gz", content_encoding: "gzip")` above the `Lucky::StaticFileHandler.new`.
#### GZip text responses
* Make [these changes](https://github.com/luckyframework/lucky_cli/commit/8bc002ab51cb13e67f515c4de977766f96825a18#diff-83ca1a783e82ef6f0d38f400b7c1eaa1) to `config/server.cr` to gzip text responses.
## Upgrading from 0.17 to 0.18
For a full diff of necessary changes, please see [LuckyDiff](https://luckydiff.com?from=0.17.0&to=0.18.0).
- Upgrade to crystal 0.31.1
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.31.1
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update `.crystal-version` to `0.31.1`
- Update versions in `shard.yml`
- Crystal should be `0.31.1`
- Lucky should be `~> 0.18`
- Authentic should be `~> 0.5.0`
- LuckyFlow should be `~> 0.6.0`
- Run `shards update`
### General updates
- Rename: all `render` calls in actions to `html`.
- Update: the `src/actions/errors/show.cr` file to the new format:
```crystal
class Errors::Show < Lucky::ErrorAction
DEFAULT_MESSAGE = "Something went wrong."
default_format :html
dont_report [Lucky::RouteNotFoundError]
def render(error : Lucky::RouteNotFoundError)
if html?
error_html "Sorry, we couldn't find that page.", status: 404
else
error_json "Not found", status: 404
end
end
# When the request is JSON and an InvalidOperationError is raised, show a
# helpful error with the param that is invalid, and what was wrong with it.
def render(error : Avram::InvalidOperationError)
if html?
error_html DEFAULT_MESSAGE, status: 500
else
error_json \
message: error.renderable_message,
details: error.renderable_details,
param: error.invalid_attribute_name,
status: 400
end
end
# Always keep this below other 'render' methods or it may override your
# custom 'render' methods.
def render(error : Lucky::RenderableError)
if html?
error_html DEFAULT_MESSAGE, status: error.renderable_status
else
error_json error.renderable_message, status: error.renderable_status
end
end
# If none of the 'render' methods return a response for the raised Exception,
# Lucky will use this method.
def default_render(error : Exception) : Lucky::Response
if html?
error_html DEFAULT_MESSAGE, status: 500
else
error_json DEFAULT_MESSAGE, status: 500
end
end
private def error_html(message : String, status : Int)
context.response.status_code = status
html Errors::ShowPage, message: message, status: status
end
private def error_json(message : String, status : Int, details = nil, param = nil)
json ErrorSerializer.new(message: message, details: details, param: param), status: status
end
private def report(error : Exception) : Nil
# Send to Rollbar, send an email, etc.
end
end
```
- Rename: `title` to `message` in `src/pages/errors/show_page.cr`.
- Add: `BaseSerializer` to `src/serializers/`.
```crystal
abstract class BaseSerializer < Lucky::Serializer
def self.for_collection(collection : Enumerable, *args, **named_args)
collection.map do |object|
new(object, *args, **named_args)
end
end
end
```
- Add: `require "./serializers/base_serializer"` to your `src/app.cr` above `require "./serializers/**"`
- Optional: Update all serializers to inherit from `BaseSerializer`. Also merge Show/Index serializers in to a single class.
```crystal
# Merge these two classes
class Users::IndexSerializer < Lucky::Serializer
end
class Users::ShowSerializers < Lucky::Serializer
end
# in to this class
class UserSerializer < BaseSerializer
# Same contents as Users::ShowSerializer
# Calls to Users::IndexSerializer now become:
#
# UserSerializer.for_collection(users)
end
```
- Rename: `Errors::ShowSerializer` to `ErrorSerializer`
- Update: `ErrorSerializer` to inherit from the new `BaseSerializer`
- Update: `ErrorSerializer` contents with:
```crystal
class ErrorSerializer < BaseSerializer
def initialize(
@message : String,
@details : String? = nil,
@param : String? = nil # If there was a problem with a specific param
)
end
def render
{message: @message, param: @param, details: @details}
end
end
```
- Add: `Avram::SchemaEnforcer.ensure_correct_column_mappings!` to `src/start_server.cr` below `Avram::Migrator::Runner.new.ensure_migrated!`.
- Update: any mention to renamed errors in [this commit](https://github.com/luckyframework/lucky/pull/911/files#diff-02d01a64649367eb50f82f303c2d07e2R248). You can likely ignore this as most people do not rescue these specific errors.
- Add: `accepted_formats [:json]` to `ApiAction` in `src/actions/api_action.cr`.
```crystal
abstract class ApiAction < Lucky::Action
accepted_formats [:json]
end
```
- Add: `accepted_formats [:html, :json], default: :html` to `BrowserAction` in `src/actions/browser_action.cr`
```crystal
abstract class BrowserAction < Lucky::Action
accepted_formats [:html, :json], default: :html
end
```
- Update: `src/app_server.cr` with explicit return type on the `middleware` method.
```crystal
# Add return type here
def middleware : Array(HTTP::Handler)
[
# ...
] of HTTP::Handler # Add this or app will fail to compile
end
```
- Add: `include Lucky::RequestExpectations` to `spec/spec_helper.cr` below `include Carbon::Expectations`
- Add: `Avram::SchemaEnforcer.ensure_correct_column_mappings!` to `spec/spec_helper.cr` below `Avram::Migrator::Runner.new.ensure_migrated!`
- Update: Change `at_exit do` in `spec/setup/start_app_server.cr` to `Spec.after_suite do`
## Upgrading from 0.16 to 0.17
- Ensure you've upgraded to crystal 0.30.1
- Upgrade Lucky CLI (homebrew)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.30.1
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
- Update `.crystal-version` to `0.30.1`
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 0.17`
- Run `shards update`
### Example upgrade
If you're not sure about an upgrade step, or simply want to look at an example, see the [lucky_bits upgrade](https://github.com/edwardloveall/lucky_bits/commit/47473a19084f1781062ce3767e3fbcf527c11e4d).
### General updates
- Rename: Action rendering method `text` to `plain_text`.
- Update: use of `number_to_currency` now returns a String instead of writing to the view directly.
- Delete: `config/static_file_handler.cr`.
- Add: a new `Lucky::LogHandler` configure to the bottom of `config/logger.cr`.
- Update: `Avram::Repo.configure` to `Avram.configure` in `config/logger.cr`.
config/logger.cr
```crystal
require "file_utils"
logger =
if Lucky::Env.test?
# Logs to `tmp/test.log` so you can see what's happening without having
# a bunch of log output in your specs results.
FileUtils.mkdir_p("tmp")
Dexter::Logger.new(
io: File.new("tmp/test.log", mode: "w"),
level: Logger::Severity::DEBUG,
log_formatter: Lucky::PrettyLogFormatter
)
elsif Lucky::Env.production?
# This sets the log formatter to JSON so you can parse the logs with
# services like Logentries or Logstash.
#
# If you want logs like in development use `Lucky::PrettyLogFormatter`.
Dexter::Logger.new(
io: STDOUT,
level: Logger::Severity::INFO,
log_formatter: Dexter::Formatters::JsonLogFormatter
)
else
# For development, log everything to STDOUT with the pretty formatter.
Dexter::Logger.new(
io: STDOUT,
level: Logger::Severity::DEBUG,
log_formatter: Lucky::PrettyLogFormatter
)
end
Lucky.configure do |settings|
settings.logger = logger
end
Lucky::LogHandler.configure do |settings|
# Skip logging static assets in development
if Lucky::Env.development?
settings.skip_if = ->(context : HTTP::Server::Context) {
context.request.method.downcase == "get" &&
context.request.resource.starts_with?(/\/css\/|\/js\/|\/assets\//)
}
end
end
Avram.configure do |settings|
settings.logger = logger
end
```
- Update: `script/setup` to include the new postgres checks.
```diff
# This must go *after* the 'shards install' step
+ printf "\nâ–¸ Checking that postgres is installed\n"
+ check_postgres | indent
+ printf "✔ Done\n" | indent
+ printf "\nâ–¸ Verifying postgres connection\n"
+ lucky db.verify_connection | indent
printf "\nâ–¸ Setting up the database\n"
lucky db.create | indent
```
### Database updates
- Add: a new `AppDatabase` class in `src/app_database.cr` that inherits from `Avram::Database`.
```crystal
class AppDatabase < Avram::Database
end
```
- Add: `require "./app_database"` to `src/app.cr` right below the `require "./shards"`.
- Rename: `Avram::Repo.configure` to `AppDatabase.configure` in `config/database.cr`.
- Add: `Avram.configure` block.
config/database.cr
```crystal
database_name = "..."
AppDatabase.configure do |settings|
if Lucky::Env.production?
settings.url = ENV.fetch("DATABASE_URL")
else
settings.url = ENV["DATABASE_URL"]? || Avram::PostgresURL.build(
database: database_name,
hostname: ENV["DB_HOST"]? || "localhost",
# Some common usernames are "postgres", "root", or your system username (run 'whoami')
username: ENV["DB_USERNAME"]? || "postgres",
# Some Postgres installations require no password. Use "" if that is the case.
password: ENV["DB_PASSWORD"]? || "postgres"
)
end
end
Avram.configure do |settings|
settings.database_to_migrate = AppDatabase
# this is moved from your old `Avram::Repo.configure` block.
settings.lazy_load_enabled = Lucky::Env.production?
end
```
- Move: the `settings.lazy_load_enabled` from `AppDatabase.configure` to `Avram.configure` block.
- Add: a `database` class method to `src/models/base_model.cr` that returns `AppDatabase`.
```crystal
abstract class BaseModel < Avram::Model
def self.database : Avram::Database.class
AppDatabase
end
end
```
- Update: `Avram::Repo` to `AppDatabase` in `spec/setup/clean_database.cr`.
- Avram no longer automatically adds a timestamp and primary key to migrations.
Add a primary key and timestamps to your old migrations.
> Also note that the syntax for a UUID has changed. You use
> `primary_key id : UUID` instead of an option on 'create'
```crystal
def migrate
create :users do
# Add these to your 'create' statements in your migrations
primary_key id : Int64 # Or 'UUID' if using UUID
add_timestamps
end
end
```
- Note: Avram now defaults primary keys to `Int64` instead of `Int32`. You
can use the `change_type` macro to migrate your **primary keys and foreign keys**
to `Int64` if you need. Run `lucky gen.migration UpdatePrimaryKeyTypes`.
```crystal
class UpdatePrimaryKeyTypesV20190723233131 < Avram::Migrator::Migration::V1
def migrate
alter table_for(User) do
change_type id : Int64
end
alter table_for(Post) do
change_type id : Int64
change_type user_id : Int64
end
end
end
```
- Update: models now default the primary key to `Int64`. This can be
overridden if your tables uses a different column type for your primary keys,
such as Int32 or UUID
```crystal
abstract class BaseModel < Avram::Model
macro default_columns
primary_key id : UUID
timestamps
end
end
```
This also means that any model that uses `UUID` for a primary key can remove the `primary_key_type` option
```crystal
class User < BaseModel
# 0.16 and earlier
table :users, primary_key_type: :uuid do
column email : String
end
# Now with 0.17 it will use the 'default_columns' from the 'BaseModel'
table :users do
column email : String
end
end
```
### Updating queries
- Rename: `Query.new.destroy_all` to `Query.truncate`. (e.g. `UserQuery.new.destroy_all` => `UserQuery.truncate`)
- Rename: all association query methods from the association name to `where_{association_name}`. (e.g. `UserQuery.new.posts` => `UserQuery.new.where_posts`)
- Update: all association query methods no longer take a block. Pass the query in as an argument. (e.g. `UserQuery.new.posts { |post_query| }` => `UserQuery.new.where_posts(PostQuery.new)`)
- Update: `where_{association_name}` methods no longer need to be preceded by a `join_{assoc}`, unless you need a custom join (i.e. `left_join_{assoc}`). If you use a custom join, you will need to add the `auto_inner_join: false` option to your `where_{assoc}` method.
### Moving forms to operations
- Rename: the `src/forms` directory to `src/operations`.
- Update: `require "./forms/mixins/**"` and `require "./forms/**"` to `require "./operations/mixins/**"` and `require "./operations/**"` respectively in `src/app.cr`
- Rename: `BaseForm` to `SaveOperation` in `src/operations`. (e.g. `User::BaseForm` => `User::SaveOperation`)
- Rename: `fillable` to `permit_columns`
- Rename: form class names to new naming convention. (e.g. `class UserForm < User::SaveOperation` => `class SaveUser < User::SaveOperation`). This step is optional, but still recommended to avoid future confusion.
- Rename: `Avram::VirtualForm` to `Avram::Operation`.
- Rename: virtual form class names to new naming convention VerbNoun. (e.g. `class SignInForm < Avram::Operation` => `class SignInUser < Avram::Operation`).
- Rename: `virtual` to `attribute`.
- Update: all `SaveOperation` classes to call `before_save prepare`. The `prepare` method is no longer called by default, which allows you to rename this method as well.
- Update: `FillableField` to `PermittedAttribute` in `src/components/shared/`. Check `field.cr` and `field_errors.cr`.
- Update: all authentic classes and modules to use new operation setup. This may require renaming some files to fit the `VerbNoun` `verb_noun.cr` convention.
Files in src/operations/
```diff
# src/operations/mixins/password_validations.cr
module PasswordValidations
+ macro included
+ before_save run_password_validations
+ end
#...
end
# src/operations/request_password_reset.cr
- class RequestPasswordReset < Avram::VirtualForm
+ class RequestPasswordReset < Avram::Operation
#...
end
# src/operations/reset_password.cr
- def prepare
- run_password_validations
+ before do
Authentic.copy_and_encrypt password, to: encrypted_password
# src/operations/sign_in_user.cr
- class SignInUser < Avram::VirtualOperation
+ class SignInUser < Avram::Operation
# src/operations/sign_up_user.cr
- def prepare
+ before_save do
validate_uniqueness_of email
- run_password_validations
```
- Update `sign_in_user.cr` to match [the new template](https://github.com/luckyframework/lucky_cli/blob/c45e1860751bba25a16120402f93e7537c0be5b5/src/base_authentication_app_skeleton/src/operations/sign_in_user.cr).
- Rename the `FindAuthenticatable` mixin to `UserFromEmail`, again the Lucky CLI [template](https://github.com/luckyframework/lucky_cli/blob/c45e1860751bba25a16120402f93e7537c0be5b5/src/base_authentication_app_skeleton/src/operations/mixins/user_from_email.cr) is a helpful guide.
## Upgrading from 0.15 to 0.16
- Upgrade to crystal 0.30.0
No updates to Lucky itself are required. There may be Crystal 0.30.0 related changes you may need to make.
## Upgrading from 0.14 to 0.15
- Upgrade to crystal 0.29.0
- Upgrade Lucky CLI (macOS)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.29.0
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
- Update `.crystal-version` to `0.29.0`
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/getting-started/installing#on-linux
- Update versions in `shard.yml`
- Lucky should be `~> 0.15`
- Run `shards update`
- Rename `src/server.cr` to `src/start_server.cr`.
- Edit `src/start_server.cr` by changing
* `app` to `app_server` and `App` to `AppServer`.
* delete the line that starts with `puts "Listening on`
- Update `src/{your app name}.cr` to require `./start_server`
- Rename `src/dependencies.cr` to `src/shards.cr`
- Move the `App` class to a new file in `src/app_server.cr`
- Rename `App` to `AppServer` and rename `Lucky::BaseApp` to `Lucky::BaseAppServer` in your new `src/app_server.cr`
- Update `src/app.cr` to require new `./app_server` file
- Update `src/app.cr` to require new `./shards` file
- Replace usages of `Lucky::Action::Status::` with the respective crystal `HTTP::Status::`
## Upgrading from 0.13 to 0.14
- Upgrade to crystal 0.28.0
- Create new file `config/force_ssl_handler.cr` with the following content:
```crystal
Lucky::ForceSSLHandler.configure do |settings|
settings.enabled = Lucky::Env.production?
end
```
## Upgrading from 0.12 to 0.13
- Upgrade Lucky CLI (macOS)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.27.2
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
- Update `.crystal-version` to `0.27.2`
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/installing/#install-lucky
- Update versions in `shard.yml`
- Lucky should be `~> 0.13`
- LuckyFlow should be `~> 0.4`
- Authentic should be `~> 0.3`
- Run `shards update`
- Find and replace `LuckyRecord` with `Avram`
- Add `Lucky::AssetHelpers.load_manifest` below `require "dependencies"` in `src/app.cr` for browser apps. Skip for API only apps.
- `Query#preload` with a query now includes the association name -> [`Query#preload_{{ assoc_name }}`](https://github.com/luckyframework/lucky_record/pull/307)
- Remove `unexpose` and `unexpose_if_exposed` from your actions. Pages now
ignore unused exposures so these methods have been removed.
- Change `require "lucky_record"` to `require "avram"` in `src/dependencies`
- Rename `config/log_handler.cr` to `config/logger.cr`
- Replace `config/logger.cr` with this:
```crystal
require "file_utils"
logger =
if Lucky::Env.test?
# Logs to `tmp/test.log` so you can see what's happening without having
# a bunch of log output in your specs results.
FileUtils.mkdir_p("tmp")
Dexter::Logger.new(
io: File.new("tmp/test.log", mode: "w"),
level: Logger::Severity::DEBUG,
log_formatter: Lucky::PrettyLogFormatter
)
elsif Lucky::Env.production?
# This sets the log formatter to JSON so you can parse the logs with
# services like Logentries or Logstash.
#
# If you want logs like in development use `Lucky::PrettyLogFormatter`.
Dexter::Logger.new(
io: STDOUT,
level: Logger::Severity::INFO,
log_formatter: Dexter::Formatters::JsonLogFormatter
)
else
# For development, log everything to STDOUT with the pretty formatter.
Dexter::Logger.new(
io: STDOUT,
level: Logger::Severity::DEBUG,
log_formatter: Lucky::PrettyLogFormatter
)
end
Lucky.configure do |settings|
settings.logger = logger
end
Avram::Repo.configure do |settings|
settings.logger = logger
end
```
- If using `is` in queries, rename the calls to `eq`
- App in `src/app.cr` should now inherit from `Lucky::BaseApp`. See [the changes you need to make](https://github.com/luckyframework/lucky_cli/commit/7794306c55b8e00ded0d816def5cd62dc6fe4367).
- Move `bin/setup` to `script/setup`
- In your `README` replace `bin/setup` with `script/setup`
- Replace `bin/lucky` in your `.gitignore` with just `/bin/`. Lucky projects
should now put bash scripts in `/script`. Binaries go in `/bin/` and are
ignored.
- `id` in actions using `route` now have the underscored version of the
resource name prepended. You'll need to rename your `id` calls to
`_id`.
```crystal
# Example from v0.12
class Users::Show < BrowserAction
route do
# Using the 'id' param
UserQuery.find(id)
end
end
# Would now be
class Users::Show < BrowserAction
route do
# Now it is 'user_id'
UserQuery.find(user_id)
end
end
```
- Make changes to [laravel.mix](https://github.com/luckyframework/lucky_cli/commit/88ad5af5b40f3a29c4abcb0581db505019d7003f#diff-cd19e42e70bfbcf2a12480b0b6b1f590)
- Make changes to [package.json](https://github.com/luckyframework/lucky_cli/commit/88ad5af5b40f3a29c4abcb0581db505019d7003f#diff-73db280623fcd1a64ac1ab76c8700dbc)
- Run `yarn install`
And you should now be good to go!
## Upgrading from 0.11 to 0.12
- Upgrade Lucky CLI (macOS)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date. Requires 0.27
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/installing/#install-lucky
> Use your package manager to update Crystal to v0.27
- In `db/migrations`, change `LuckyMigrator::Migration` -> `LuckyRecord::Migrator::Migration` for every migration
- Remove `lucky_migrator` from `shard.yml`
- Remove `lucky_migrator` from `src/dependencies`
- Remove the `LuckyMigrator.configure` block from `config/database.cr`
- Configuration now requires passing an argument. Find and replace `.configure do` with `.configure do |settings|` in all files in `config`
- Update `config/session.cr`
- Change `Lucky::Session::Store.configure` to `Lucky::Session.configure do |settings|`
- Change your session key because signing/encryption has changed. For example: add `_0_12_0` to the end of the key.
- Remove `settings.secret = Lucky::Server.settings.secret_key_base`
- If using `cookies[]` anywhere in your app, change the key you use. Lucky now signs and encrypts all cookies. Old cookies will not decrypt properly.
- Change `session[]=` and `cookies[]=` to `session|cookies.set|get`
- Change `session|cookies.destroy` to `session/cookies.clear`
- `cookies.unset(:key)` and `delete.unset(:key)` should be `cookies|session.delete(:key)`
- Remove `unexpose current_user` from `src/actions/home/index.cr`
- `Query#count` has been renamed to `Query#select_count`. For example: `UserQuery.new.count` is now `UserQuery.new.select_count`
- Change `flash.danger` to `flash.failure` in your actions.
- Update `Lucky::Flash::Handler` to `Lucky::FlashHandler` in `src/app.cr`
- Update usages of `Lucky::Response` to `Lucky::TextResponse`
- Update usages of `LuckyInflector::Inflector` to `Wordsmith::Inflector`
- Remove `config/session.cr` and copy [`config/cookies.cr`](https://github.com/luckyframework/lucky_cli/blob/baaeeb0b8c7a410625320af394437f8665442664/src/web_app_skeleton/config/cookies.cr.ecr)
- Replace `config/email.cr` with [this one](https://github.com/luckyframework/lucky_cli/blob/baaeeb0b8c7a410625320af394437f8665442664/src/web_app_skeleton/config/email.cr).
- Add this line to `spec_helper.cr` (around line 19) -> `LuckyRecord::Migrator::Runner.new.ensure_migrated!`
- In `config/server.cr`, copy the new block starting at [`line 15`](https://github.com/luckyframework/lucky_cli/blob/baaeeb0b8c7a410625320af394437f8665442664/src/web_app_skeleton/config/server.cr.ecr#L15-L23).
- Update shard versions in `shard.yml`:
- Lucky `~> 0.12`
- LuckyRecord `~> 0.7`
- Authentic `~> 0.2`
- LuckyFlow `~> 0.3`
- Change `.crystal-version` to `0.27.0`
- Run `shards update` to install the new shards
## Upgrading from 0.10 to 0.11
- Upgrade Lucky CLI (macOS)
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date
brew upgrade lucky
```
- Upgrade Lucky CLI (Linux)
> Remove the existing Lucky binary and follow the Linux
> instructions in this section
> https://luckyframework.org/guides/installing/#install-lucky
> Use your package manager to update Crystal to v0.25
- Update `.crystal-version` to `0.25.0`
- Change `crystal deps` to `shards install` in `bin/setup`
- Update `lucky_flow` and `lucky_migrator` in `shard.yml`
- `lucky_flow` should now be `0.2`
- `lucky_migrator` should now be `0.6`
- Remove any cached shards: rm -rf ~/.cache/shards
> This is to address a bug in shards: https://github.com/crystal-lang/shards/issues/211
- Run `shards update`
- Find all instances of `nested_action` and replace with `nested_route`
- Find all instances of `action` and replace with `route` in your actions
> To make it easier to only change the right thing, search for `action do` and
> replace with `route do`. This will make it fairly easy to find and replace
> across your whole project.
- Move static assets from `static/assets` to `public/assets`
- Move `static/js` to `src/js`
- Move `static/css` to `src/css`
- Remove `/public` from `.gitignore`
- Add these to `.gitignore`
- `/public/mix-manifest.json`
- `/public/js`
- `/public/css`
- Update `src/app.cr` lines:
- Remove host and port: https://github.com/luckyframework/lucky_cli/blob/ce677b8aefbbef2f06587d835795cbb59c5801dd/src/web_app_skeleton/src/app.cr.ecr#L25
- Add `bind_tcp` with host and port: https://github.com/luckyframework/lucky_cli/blob/ce677b8aefbbef2f06587d835795cbb59c5801dd/src/web_app_skeleton/src/app.cr.ecr#L50
- Update webpack config to match this: https://github.com/luckyframework/lucky_cli/blob/ce677b8aefbbef2f06587d835795cbb59c5801dd/src/browser_app_skeleton/webpack.mix.js#L12-L37
- Calls to the `asset` method no longer require prefixing `/assets`. You may not
be using this. The compiler will complain and help you find the right asset if
you need to update this.
### Upgrading from 0.8 to 0.10
> Note: Lucky skipped version 0.9 so that Lucky and Lucky CLI are on the same version.
- Upgrade Lucky CLI
On macOS:
```
brew update
brew upgrade crystal-lang # Make sure you're up-to-date
brew upgrade lucky
```
If you are on Linux, remove the existing Lucky binary and follow the Linux
instructions in this section
https://luckyframework.org/guides/installing/#install-lucky
- View the upgrade diff and make changes to your app
In previous upgrade guides (below) every change is listed individually. This was
time consuming and error-prone. Now,
you can [view all changes in this GitHub commit](https://github.com/luckyframework/upgrade-diffs/commit/c279b0d0c0b9936301c5ea93fd25a549c9cd4c06).
- Ensure node version is at least 6.0 `node -v`. Install a newer version if
yours is older.
- Move files in `src/pipes` to `src/actions/mixins`
- Change `allow` to `fillable` in forms
- Change `allow_virtual` to `virtual` in forms
- Run `shards update`
- Run `bin/setup` to run new migrations, Laravel Mix and seeds file
> If you have any problems or want to add extra details please open an issue or
> Pull Request. Thank you!
### Upgrading from 0.7 to 0.8
- Upgrade Lucky CLI
On macOS:
```
brew update
brew upgrade crystal-lang
brew upgrade lucky
```
If you are on Linux, remove the existing Lucky binary and follow the Linux
instructions in this section:
https://luckyframework.org/guides/installing/#install-lucky
- Update dependencies in `shard.yml`
```yml
dependencies:
lucky:
github: luckyframework/lucky
version: "~> 0.8.0"
lucky_migrator:
github: luckyframework/lucky_migrator
version: ~> 0.4.0
```
Then run `shards update`
- Update `config/server.cr`
You can probably copy this as-is, but if you have made customizations to your
`config/server.cr` then you'll need to customize this:
```crystal
Lucky::Server.configure do |settings|
if Lucky::Env.production?
settings.secret_key_base = secret_key_from_env
settings.host = "0.0.0.0"
settings.port = ENV["PORT"].to_i
else
settings.secret_key_base = "<%= secret_key_base %>"
# Change host/port in config/watch.yml
# Alternatively, you can set the PORT env to set the port
settings.host = Lucky::ServerSettings.host
settings.port = Lucky::ServerSettings.port
end
end
private def secret_key_from_env
ENV["SECRET_KEY_BASE"]? || raise_missing_secret_key_in_production
end
private def raise_missing_secret_key_in_production
raise "Please set the SECRET_KEY_BASE environment variable. You can generate a secret key with 'lucky gen.secret_key'"
end
```
- Add `config/watch.yml`
This is used by the watcher so it knows what port the server is running on.
```yaml
host: 0.0.0.0
port: 5000
```
- Update `config/database.cr`
Put this inside of the `LuckyRecord::Repo.configure do |settings|` block:
```
# In development and test, raise an error if you forget to preload associations
settings.lazy_load_enabled = Lucky::Env.production?
```
See a full example here: https://github.com/luckyframework/lucky_cli/blob/a25472cc7461b1803735d086e57a632f92f93a1c/src/web_app_skeleton/config/database.cr.ecr
- You will need to preload associations now:
This will make N+1 queries a thing of the past.
```crystal
# Will now raise a runtime error in dev/test
post = PostQuery.new.find(id)
post.comments # Must preload comments
# Now, you need to preload the comments
post = PostQuery.new.preload_comments.find(id)
post.comments
```
- Rename `field` to `column` in your models. For example
```crystal
class Post < BaseModel
table :posts do
  column title : String # was "field title : String" previously
 end
end
```
- Optionally include `responsive_meta_tag` in `MainLayout`
You can include this in `head` to make your app layout responsive.
- Change `abstract def inner` to `abstract def content` in `MainLayout`
- Change method call to `inner` to `content` in the render method of `MainLayout`
- Change instances of `def inner` to `def content` in Pages
- Change form `needs` to use `on: :create`
`needs` in forms should now use `on: :save` if you want the old behavior.
See https://luckyframework.org/guides/saving-with-forms/#passing-extra-data-to-forms for more info
- Must pass extra params using `create` or `update`
You can no longer pass params to `Form#new`. You must pass them in the
`create` or `update`.
```crystal
UserForm.new(name: "Jane").save!
UserForm.create!(name: "Jane")
```
More info at https://luckyframework.org/guides/saving-with-forms/#passing-data-without-route-params
- Change calls from `form.save_succeeded?` to `form.saved?`
- Trap int in src/server.cr
Add this to your `src/server.cr` before `server.listen`
```crystal
Signal::INT.trap do
server.close
end
```
- Add `bin/lucky/` to `.gitignore`
```
# Add to .gitignore
bin/lucky/
```
- Add nice HTML error page
Copy contents of the linked file to `src/pages/errors/show_page.cr`
https://github.com/luckyframework/lucky_cli/blob/a25472cc7461b1803735d086e57a632f92f93a1c/src/web_app_skeleton/src/pages/errors/show_page.cr
- Add default `Error::ShowSerializer`
This is used for serializing errors to JSON. Add this to
`src/serializers/errors/show_serializer.cr`
```crystal
# This is the default error serializer generated by Lucky.
# Feel free to customize it in any way you like.
class Errors::ShowSerializer < Lucky::Serializer
def initialize(@message : String, @details : String? = nil)
end
def render
{message: @message, details: @details}
end
end
```
- Update `Errors::Show` action
The error handling action now supports more errors and renders better output.
Copy the contents of the linked file to `src/actions/errors/show.cr`
https://github.com/luckyframework/lucky_cli/blob/a25472cc7461b1803735d086e57a632f92f93a1c/src/web_app_skeleton/src/actions/errors/show.cr
- Require serializers
Add the following to `src/app.cr`.
```crystal
require "./serializers/**"
```
### Upgrading from 0.6 to 0.7
- Update to Crystal v0.24.1. Lucky will fail on earlier versions
```
brew update
brew upgrade crystal-lang
brew upgrade lucky
```
If you are on Linux, remove the existing Lucky binary and follow the Linux instructions in this section: https://luckyframework.org/guides/installing/#install-lucky
- Update dependencies in `shard.yml`
```yml
dependencies:
lucky:
github: luckyframework/lucky
version: "~> 0.7.0"
lucky_migrator:
github: luckyframework/lucky_migrator
version: ~> 0.4.0
```
Then run `shards update`
- Configure the domain to use for the RouteHelper:
```crystal
# Add to config/route_helper.cr
Lucky::RouteHelper.configure do |settings|
if Lucky::Env.production?
# The APP_DOMAIN is something like https://myapp.com
settings.domain = ENV.fetch("APP_DOMAIN")
else
settings.domain = "http:://localhost:3001"
end
end
```
- Add `csrf_meta_tags` to your `MainLayout`
```crystal
# src/pages/main_layout.cr
# Somewhere in the head tag:
csrf_meta_tags
```
- Remove `needs flash` from `MainLayout`
```crystal
# Delete this line
needs flash : Lucky::Flash::Store
```
- Remove `expose flash` from `BrowserAction` and add forgery protection
```crystal
# src/actions/browser_action.cr
abstract class BrowserAction < Lucky::Action
include Lucky::ProtectFromForgery
end
```
- Change `Shared::FlashComponent` to get the flash from `@context`
```crystal
# src/components/shared/flash_component.cr
# Change this:
@flash.each
# To:
@context.flash.each
```
- Add `*.dwarf` to the .gitignore
```
# Add to .gitignore
*.dwarf
```