aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/rails
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/rails')
-rw-r--r--activerecord/lib/rails/generators/active_record.rb19
-rw-r--r--activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb27
-rw-r--r--activerecord/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt5
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb48
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb75
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt24
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt46
-rw-r--r--activerecord/lib/rails/generators/active_record/model/model_generator.rb49
-rw-r--r--activerecord/lib/rails/generators/active_record/model/templates/model.rb.tt13
-rw-r--r--activerecord/lib/rails/generators/active_record/model/templates/module.rb.tt7
10 files changed, 313 insertions, 0 deletions
diff --git a/activerecord/lib/rails/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb
new file mode 100644
index 0000000000..a7e5e373a7
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require "rails/generators/named_base"
+require "rails/generators/active_model"
+require "rails/generators/active_record/migration"
+require "active_record"
+
+module ActiveRecord
+ module Generators # :nodoc:
+ class Base < Rails::Generators::NamedBase # :nodoc:
+ include ActiveRecord::Generators::Migration
+
+ # Set the current directory as base for the inherited generators.
+ def self.base_root
+ __dir__
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb
new file mode 100644
index 0000000000..35d5664400
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/application_record/application_record_generator.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require "rails/generators/active_record"
+
+module ActiveRecord
+ module Generators # :nodoc:
+ class ApplicationRecordGenerator < ::Rails::Generators::Base # :nodoc:
+ source_root File.expand_path("templates", __dir__)
+
+ # FIXME: Change this file to a symlink once RubyGems 2.5.0 is required.
+ def create_application_record
+ template "application_record.rb", application_record_file_name
+ end
+
+ private
+
+ def application_record_file_name
+ @application_record_file_name ||=
+ if namespaced?
+ "app/models/#{namespaced_path}/application_record.rb"
+ else
+ "app/models/application_record.rb"
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt b/activerecord/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt
new file mode 100644
index 0000000000..60050e0bf8
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt
@@ -0,0 +1,5 @@
+<% module_namespacing do -%>
+class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+end
+<% end -%>
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
new file mode 100644
index 0000000000..cbb88d571d
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require "rails/generators/migration"
+
+module ActiveRecord
+ module Generators # :nodoc:
+ module Migration
+ extend ActiveSupport::Concern
+ include Rails::Generators::Migration
+
+ module ClassMethods
+ # Implement the required interface for Rails::Generators::Migration.
+ def next_migration_number(dirname)
+ next_migration_number = current_migration_number(dirname) + 1
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
+ end
+ end
+
+ private
+
+ def primary_key_type
+ key_type = options[:primary_key_type]
+ ", id: :#{key_type}" if key_type
+ end
+
+ def db_migrate_path
+ if defined?(Rails.application) && Rails.application
+ configured_migrate_path || default_migrate_path
+ else
+ "db/migrate"
+ end
+ end
+
+ def default_migrate_path
+ Rails.application.config.paths["db/migrate"].to_ary.first
+ end
+
+ def configured_migrate_path
+ return unless database = options[:database]
+ config = ActiveRecord::Base.configurations.configs_for(
+ env_name: Rails.env,
+ spec_name: database,
+ )
+ config&.migrations_paths
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
new file mode 100644
index 0000000000..dd79bcf542
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require "rails/generators/active_record"
+
+module ActiveRecord
+ module Generators # :nodoc:
+ class MigrationGenerator < Base # :nodoc:
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
+
+ class_option :primary_key_type, type: :string, desc: "The type for primary key"
+ class_option :database, type: :string, aliases: %i(db), desc: "The database for your migration. By default, the current environment's primary database is used."
+
+ def create_migration_file
+ set_local_assigns!
+ validate_file_name!
+ migration_template @migration_template, File.join(db_migrate_path, "#{file_name}.rb")
+ end
+
+ private
+ attr_reader :migration_action, :join_tables
+
+ # Sets the default migration template that is being used for the generation of the migration.
+ # Depending on command line arguments, the migration template and the table name instance
+ # variables are set up.
+ def set_local_assigns!
+ @migration_template = "migration.rb"
+ case file_name
+ when /^(add)_.*_to_(.*)/, /^(remove)_.*?_from_(.*)/
+ @migration_action = $1
+ @table_name = normalize_table_name($2)
+ when /join_table/
+ if attributes.length == 2
+ @migration_action = "join"
+ @join_tables = pluralize_table_names? ? attributes.map(&:plural_name) : attributes.map(&:singular_name)
+
+ set_index_names
+ end
+ when /^create_(.+)/
+ @table_name = normalize_table_name($1)
+ @migration_template = "create_table_migration.rb"
+ end
+ end
+
+ def set_index_names
+ attributes.each_with_index do |attr, i|
+ attr.index_name = [attr, attributes[i - 1]].map { |a| index_name_for(a) }
+ end
+ end
+
+ def index_name_for(attribute)
+ if attribute.foreign_key?
+ attribute.name
+ else
+ attribute.name.singularize.foreign_key
+ end.to_sym
+ end
+
+ def attributes_with_index
+ attributes.select { |a| !a.reference? && a.has_index? }
+ end
+
+ # A migration file name can only contain underscores (_), lowercase characters,
+ # and numbers 0-9. Any other file name will raise an IllegalMigrationNameError.
+ def validate_file_name!
+ unless /^[_a-z0-9]+$/.match?(file_name)
+ raise IllegalMigrationNameError.new(file_name)
+ end
+ end
+
+ def normalize_table_name(_table_name)
+ pluralize_table_names? ? _table_name.pluralize : _table_name.singularize
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt
new file mode 100644
index 0000000000..5f7201cfe1
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt
@@ -0,0 +1,24 @@
+class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
+ def change
+ create_table :<%= table_name %><%= primary_key_type %> do |t|
+<% attributes.each do |attribute| -%>
+<% if attribute.password_digest? -%>
+ t.string :password_digest<%= attribute.inject_options %>
+<% elsif attribute.token? -%>
+ t.string :<%= attribute.name %><%= attribute.inject_options %>
+<% else -%>
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
+<% end -%>
+<% end -%>
+<% if options[:timestamps] %>
+ t.timestamps
+<% end -%>
+ end
+<% attributes.select(&:token?).each do |attribute| -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
+<% end -%>
+<% attributes_with_index.each do |attribute| -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+<% end -%>
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt
new file mode 100644
index 0000000000..481c70201b
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/migration/templates/migration.rb.tt
@@ -0,0 +1,46 @@
+class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
+<%- if migration_action == 'add' -%>
+ def change
+<% attributes.each do |attribute| -%>
+ <%- if attribute.reference? -%>
+ add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
+ <%- elsif attribute.token? -%>
+ add_column :<%= table_name %>, :<%= attribute.name %>, :string<%= attribute.inject_options %>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
+ <%- else -%>
+ add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
+ <%- if attribute.has_index? -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ <%- end -%>
+<%- end -%>
+ end
+<%- elsif migration_action == 'join' -%>
+ def change
+ create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
+ <%- attributes.each do |attribute| -%>
+ <%- if attribute.reference? -%>
+ t.references :<%= attribute.name %><%= attribute.inject_options %>
+ <%- else -%>
+ <%= '# ' unless attribute.has_index? -%>t.index <%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ <%- end -%>
+ end
+ end
+<%- else -%>
+ def change
+<% attributes.each do |attribute| -%>
+<%- if migration_action -%>
+ <%- if attribute.reference? -%>
+ remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
+ <%- else -%>
+ <%- if attribute.has_index? -%>
+ remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ remove_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
+ <%- end -%>
+<%- end -%>
+<%- end -%>
+ end
+<%- end -%>
+end
diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
new file mode 100644
index 0000000000..eac504f9f1
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require "rails/generators/active_record"
+
+module ActiveRecord
+ module Generators # :nodoc:
+ class ModelGenerator < Base # :nodoc:
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
+
+ check_class_collision
+
+ class_option :migration, type: :boolean
+ class_option :timestamps, type: :boolean
+ class_option :parent, type: :string, desc: "The parent class for the generated model"
+ class_option :indexes, type: :boolean, default: true, desc: "Add indexes for references and belongs_to columns"
+ class_option :primary_key_type, type: :string, desc: "The type for primary key"
+ class_option :database, type: :string, aliases: %i(db), desc: "The database for your model's migration. By default, the current environment's primary database is used."
+
+ # creates the migration file for the model.
+ def create_migration_file
+ return unless options[:migration] && options[:parent].nil?
+ attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
+ migration_template "../../migration/templates/create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
+ end
+
+ def create_model_file
+ template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
+ end
+
+ def create_module_file
+ return if regular_class_path.empty?
+ template "module.rb", File.join("app/models", "#{class_path.join('/')}.rb") if behavior == :invoke
+ end
+
+ hook_for :test_framework
+
+ private
+
+ def attributes_with_index
+ attributes.select { |a| !a.reference? && a.has_index? }
+ end
+
+ # Used by the migration template to determine the parent name of the model
+ def parent_class_name
+ options[:parent] || "ApplicationRecord"
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/rails/generators/active_record/model/templates/model.rb.tt b/activerecord/lib/rails/generators/active_record/model/templates/model.rb.tt
new file mode 100644
index 0000000000..55dc65c8ad
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/model/templates/model.rb.tt
@@ -0,0 +1,13 @@
+<% 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? %><%= ', required: true' if attribute.required? %>
+<% end -%>
+<% attributes.select(&:token?).each do |attribute| -%>
+ has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
+<% end -%>
+<% if attributes.any?(&:password_digest?) -%>
+ has_secure_password
+<% end -%>
+end
+<% end -%>
diff --git a/activerecord/lib/rails/generators/active_record/model/templates/module.rb.tt b/activerecord/lib/rails/generators/active_record/model/templates/module.rb.tt
new file mode 100644
index 0000000000..a3bf1c37b6
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/model/templates/module.rb.tt
@@ -0,0 +1,7 @@
+<% module_namespacing do -%>
+module <%= class_path.map(&:camelize).join('::') %>
+ def self.table_name_prefix
+ '<%= namespaced? ? namespaced_class_path.join('_') : class_path.join('_') %>_'
+ end
+end
+<% end -%>