diff options
6 files changed, 82 insertions, 6 deletions
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb index d3c853cfea..7a3c6f5e95 100644 --- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb +++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb @@ -55,7 +55,7 @@ module ActiveRecord def attributes_with_index attributes.select { |a| !a.reference? && a.has_index? } end - + def validate_file_name! unless file_name =~ /^[_a-z0-9]+$/ raise IllegalMigrationNameError.new(file_name) diff --git a/activerecord/lib/rails/generators/active_record/model/templates/model.rb b/activerecord/lib/rails/generators/active_record/model/templates/model.rb index 808598699b..539d969fce 100644 --- a/activerecord/lib/rails/generators/active_record/model/templates/model.rb +++ b/activerecord/lib/rails/generators/active_record/model/templates/model.rb @@ -1,7 +1,7 @@ <% module_namespacing do -%> class <%= class_name %> < <%= parent_class_name.classify %> <% attributes.select(&:reference?).each do |attribute| -%> - belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %> + belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %><%= ', required: true' if attribute.required? %> <% end -%> <% if attributes.any?(&:password_digest?) -%> has_secure_password diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 1ccdfb6589..5e2b82c3e9 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,7 @@ +* Add a `required` option to the model generator for associations + + *Sean Griffin* + * Add `after_bundle` callbacks in Rails templates. Useful for allowing the generated binstubs to be added to version control. diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index c5326d70d1..f16bd8e082 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -44,8 +44,11 @@ module Rails return $1, limit: $2.to_i when /decimal\{(\d+)[,.-](\d+)\}/ return :decimal, precision: $1.to_i, scale: $2.to_i - when /(references|belongs_to)\{polymorphic\}/ - return $1, polymorphic: true + when /(references|belongs_to)\{(.+)\}/ + type = $1 + provided_options = $2.split(/[,.-]/) + options = Hash[provided_options.map { |opt| [opt.to_sym, true] }] + return type, options else return type, {} end @@ -123,7 +126,11 @@ module Rails end def polymorphic? - self.attr_options.has_key?(:polymorphic) + self.attr_options[:polymorphic] + end + + def required? + self.attr_options[:required] end def has_index? @@ -139,12 +146,21 @@ module Rails end def inject_options - "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } + "".tap { |s| options_for_migration.each { |k,v| s << ", #{k}: #{v.inspect}" } } end def inject_index_options has_uniq_index? ? ", unique: true" : "" end + + def options_for_migration + @attr_options.dup.tap do |options| + if required? + options.delete(:required) + options[:null] = false + end + end + end end end end diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 6fac643ed0..72f5fe29ca 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -159,6 +159,18 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_add_migration_with_required_references + migration = "add_references_to_books" + run_generator [migration, "author:belongs_to{required}", "distributor:references{polymorphic,required}"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_reference :books, :author, index: true, null: false/, change) + assert_match(/add_reference :books, :distributor, polymorphic: true, index: true, null: false/, change) + end + end + end + def test_create_join_table_migration migration = "add_media_join_table" run_generator [migration, "artist_id", "musics:uniq"] diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index b67cf02d7b..8e5b556a7d 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -1,5 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/model/model_generator' +require 'active_support/core_ext/string/strip' class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -363,6 +364,49 @@ class ModelGeneratorTest < Rails::Generators::TestCase end end + def test_required_belongs_to_adds_required_association + run_generator ["account", "supplier:references{required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_polymorphic_belongs_to_generages_correct_model + run_generator ["account", "supplier:references{required,polymorphic}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_and_polymorphic_are_order_independent + run_generator ["account", "supplier:references{polymorphic.required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_adds_null_false_to_column + run_generator ["account", "supplier:references{required}"] + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.references :supplier,.*\snull: false/, up) + end + end + end + private def assert_generated_fixture(path, parsed_contents) fixture_file = File.new File.expand_path(path, destination_root) |