lib/generators/madmin/resource/resource_generator.rb in madmin-0.1.0 vs lib/generators/madmin/resource/resource_generator.rb in madmin-0.1.1
- old
+ new
@@ -1,76 +1,112 @@
-require "rails/generators/named_base"
-require "madmin/generator_helpers"
-
module Madmin
module Generators
class ResourceGenerator < Rails::Generators::NamedBase
- ATTRIBUTE_TYPE_MAPPING = {
- boolean: "Field::CheckBox",
- date: "Field::DateTime",
- datetime: "Field::DateTime",
- enum: "Field::Text",
- float: "Field::Number",
- integer: "Field::Number",
- time: "Field::DateTime",
- text: "Field::TextArea",
- string: "Field::Text",
- }
+ include Madmin::GeneratorHelpers
source_root File.expand_path("../templates", __FILE__)
- def create_resource_file
- template(
- "resource.rb.erb",
- Rails.root.join("app/madmin/resources/#{file_name}.rb"),
- )
+ def eager_load
+ Rails.application.eager_load!
end
- private
+ def generate_resource
+ template "resource.rb", "app/madmin/resources/#{file_path}_resource.rb"
+ end
- def attributes
- klass.attribute_types.map { |name, attr|
- # Skip attributes related to associations
- next if ignored_attributes.include?(name)
+ def generate_controller
+ destination = Rails.root.join("app/controllers/madmin/#{file_path.pluralize}_controller.rb")
+ template("controller.rb", destination)
+ end
- [name, madmin_type_for_column(attr.type)]
- }.compact
+ def generate_route
+ if route_namespace_exists?
+ route "resources :#{plural_name}", namespace: class_path, indentation: 4, sentinel: /namespace :madmin do\s*\n/m
+ else
+ route "resources :#{plural_name}", namespace: [:madmin] + class_path
+ end
end
+ private
+
def associations
- klass.reflections.map do |name, association|
- if association.polymorphic?
- [name, "Field::Polymorphic"]
- elsif association.belongs_to?
- [name, "Field::BelongsTo"]
- elsif association.has_one?
- [name, "Field::HasOne"]
- else
- [name, "Field::HasMany"]
+ model.reflections.reject { |name, association|
+ # Hide these special associations
+ name.starts_with?("rich_text") ||
+ name.ends_with?("_attachment") ||
+ name.ends_with?("_attachments") ||
+ name.ends_with?("_blob") ||
+ name.ends_with?("_blobs")
+ }.keys
+ end
+
+ def attributes
+ model.attribute_names + virtual_attributes - redundant_attributes
+ end
+
+ def virtual_attributes
+ virtual = []
+
+ # Add virtual attributes for ActionText and ActiveStorage
+ model.reflections.each do |name, association|
+ if name.starts_with?("rich_text")
+ virtual << name.split("rich_text_").last
+ elsif name.ends_with?("_attachment")
+ virtual << name.split("_attachment").first
+ elsif name.ends_with?("_attachments")
+ virtual << name.split("_attachments").first
end
end
+
+ virtual
end
- def ignored_attributes
- attrs = []
+ def redundant_attributes
+ redundant = []
- klass.reflections.map do |name, association|
- if association.polymorphic?
- attrs += [association.foreign_key, association.foreign_type]
- elsif association.belongs_to?
- attrs += [association.foreign_key]
+ model.reflections.each do |name, association|
+ if association.has_one?
+ next
+ elsif association.collection?
+ next
+ elsif association.polymorphic?
+ redundant << "#{name}_id"
+ redundant << "#{name}_type"
+ elsif name.starts_with?("rich_text")
+ redundant << name
+ else # belongs to
+ redundant << "#{name}_id"
end
end
- attrs
+ redundant
end
- def klass
- @klass ||= Object.const_get(class_name)
+ def model
+ @model ||= class_name.constantize
end
- def madmin_type_for_column(column_type)
- ATTRIBUTE_TYPE_MAPPING[column_type]
+ def formatted_options_for_attribute(name)
+ options = options_for_attribute(name)
+ return if options.blank?
+
+ ", " + options.map { |key, value|
+ "#{key}: #{value}"
+ }.join(", ")
+ end
+
+ def options_for_attribute(name)
+ if %w[id created_at updated_at].include?(name)
+ {form: false}
+
+ # Attributes without a database column
+ elsif !model.column_names.include?(name)
+ {index: false}
+
+ # Counter cache columns are typically not editable
+ elsif name.ends_with?("_count")
+ {form: false}
+ end
end
end
end
end