New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add rails db:system:change command #34832
Conversation
9342aa9
to
6e19f90
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this. I left 2 minor comments.
when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil] | ||
when "jdbcpostgresql" then ["activerecord-jdbcpostgresql-adapter", nil] | ||
when "jdbc" then ["activerecord-jdbc-adapter", nil] | ||
else [database, nil] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this raise an error if we get to the else? Otherwise I think this will silently fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, sqlite3
and ibm_db
have a direct adapter name to gem name mapping with no version locking. The value itself should be validated by the #initialize
check in ChangeGenerator
.
railties/lib/rails/generators/rails/db/system/change/change_generator.rb
Outdated
Show resolved
Hide resolved
railties/lib/rails/generators.rb
Outdated
|
||
if context | ||
lookups << "#{name}:#{context}" | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do these new lines do? I've always found the base
and context
naming here confusing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm essentially only adding lookups << "rails:#{base}:#{name}"
if a base
exists. This is necessary due to the second part of the lookup code:
unless base || context
unless name.to_s.include?(?:)
lookups << "#{name}:#{name}"
lookups << "rails:#{name}"
end
lookups << "#{name}"
end
Specifically, lookups << "rails:#{name}"
which limits us to looking up single segment generator names in the toplevel rails namespace.
When looking up rails g db:system:change
, name
is the last segment ("change"
), base
is the namespace path ("db:system"
), and context
is nil
. I think context
is used if name
isn't the command name, but I'm not sure why. Maybe we should change base
to path
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it's possible for users to call rails g db:system:change
? I thought this generator was internal and sufficiently called via it's class start
method from the command?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is currently possible, yes. If we don't want it to be possible, and only called via the command, I can remove this patch to #find_by_namespace
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go ahead and revert the changes to the generator lookup and hide this generator so it can only be called through the command. I'm assuming we would prefer only one way of changing databases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're getting pretty adept at finding your way around the codebase! Lovely to see 💪
module Db | ||
module System | ||
class ChangeCommand < Base # :nodoc: | ||
class_option :to, desc: "The DBMS to switch to." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we generally say DBMS elsewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only once in a comment of activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
. I see RDBMS
in guides/source/active_record_basics.md
and activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
, but I don't think that's much better. I'll change it to database
for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try "database type"? It's not brilliant, but maybe an improvement? Or "database platform"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using "database system" would match the command name and reinforce the concept. But it's perhaps not expounding on what a "database system" means, that meaning only comes from seeing MySQL, Postgres and the gang.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that database system
makes the most sense given the command name. Will use that
|
||
def valid_const? | ||
if /^\d/.match?(app_const) | ||
raise Error, "Invalid application name #{original_app_name}. Please give a name which does not start with numbers." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curiosity for another time: since 2.6 allows constants to start with non ascii characters, does that mean we could name a Rails app, say, 666?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kaspth not 666
, because it needs to begin with something the unicode database as included in the particular ruby version thinks is an uppercase letter. Just not limited to ascii.
railties/lib/rails/generators/rails/db/system/change/change_generator.rb
Outdated
Show resolved
Hide resolved
railties/lib/rails/generators/rails/db/system/change/change_generator.rb
Outdated
Show resolved
Hide resolved
gem 'turbolinks', '~> 5' | ||
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder | ||
gem 'jbuilder', '~> 2.5' | ||
GEMFILE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How will we have to maintain these Gemfiles going forward?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I initially tried to generate all test apps without --skip-gemfile
, but then rails will run bundle install
and crash because rails 6 isn't released yet. I just noticed we have skip_bundle
as an app generator option, so I'll try using that, and using the gem template in generator tests.
assert_match "adapter: postgresql", content | ||
assert_match "database: test_app", content | ||
end | ||
assert_file("Gemfile") do |content| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a newline after output
and between the assert_file
seems like it would increase readability in these tests.
module Command | ||
module Db | ||
module System | ||
class ChangeCommand < Base # :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For another time: seeing this deep module nesting makes me think we should consider adding something akin to Action Mailboxes' routing
for commands.
Forgot to ask, how are we handling cases where people who may have changed their |
b0a95b7
to
9c2ef0f
Compare
The generator will detect a configuration file already exists and gives options to overwrite, show a diff, reject the change, or merge the two files together. Eg.
|
9c2ef0f
to
55a27f4
Compare
2131e71
to
88e1d38
Compare
Add `rails db:system:change` command for changing databases. ``` bin/rails db:system:change --to=postgresql force config/database.yml gsub Gemfile ``` The change command copies a template `config/database.yml` with the target database adapter into your app, and replaces your database gem with the target database gem.
88e1d38
to
d49899c
Compare
I've hidden the change generator, reverted the patch to call it with |
Hey, Thanks for adding this! Edited: Seems like |
cc @gmcgibbon |
Thanks for pointing that out @bogdanvlviv, I'll see what I can do! |
We sometimes say "✂️ newline after `private`" in a code review (e.g. rails#18546 (comment), rails#34832 (comment)). Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style `EnforcedStyle: only_before` (rubocop/rubocop#7059). That cop and enforced style will reduce the our code review cost.
Add rails db:system:change command rails/rails#34832
Implementing this as a command makes it inconsistent at few places:
But it is present for
|
We sometimes say "✂️ newline after `private`" in a code review (e.g. rails/rails#18546 (comment), rails/rails#34832 (comment)). Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style `EnforcedStyle: only_before` (rubocop/rubocop#7059). That cop and enforced style will reduce the our code review cost.
Part two of #34710.
After studying up commands and generators, I decided to make a command that delegates to a generator (similar to rails new / app generator). This seems to give us the most flexibility with how the command interacts with files, and if the user wants to accept the config overwrites or not.
TODO: