diff options
Diffstat (limited to 'railties/lib/rails/generators/generated_attribute.rb')
-rw-r--r-- | railties/lib/rails/generators/generated_attribute.rb | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb new file mode 100644 index 0000000000..c5326d70d1 --- /dev/null +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -0,0 +1,150 @@ +require 'active_support/time' + +module Rails + module Generators + class GeneratedAttribute # :nodoc: + INDEX_OPTIONS = %w(index uniq) + UNIQ_INDEX_OPTIONS = %w(uniq) + + attr_accessor :name, :type + attr_reader :attr_options + attr_writer :index_name + + class << self + def parse(column_definition) + name, type, has_index = column_definition.split(':') + + # if user provided "name:index" instead of "name:string:index" + # type should be set blank so GeneratedAttribute's constructor + # could set it to :string + has_index, type = type, nil if INDEX_OPTIONS.include?(type) + + type, attr_options = *parse_type_and_options(type) + type = type.to_sym if type + + if type && reference?(type) + references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { unique: true } : true + attr_options[:index] = references_index + end + + new(name, type, has_index, attr_options) + end + + def reference?(type) + [:references, :belongs_to].include? type + end + + private + + # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to + # when declaring options curly brackets should be used + def parse_type_and_options(type) + case type + when /(string|text|binary|integer)\{(\d+)\}/ + 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 + else + return type, {} + end + end + end + + def initialize(name, type=nil, index_type=false, attr_options={}) + @name = name + @type = type || :string + @has_index = INDEX_OPTIONS.include?(index_type) + @has_uniq_index = UNIQ_INDEX_OPTIONS.include?(index_type) + @attr_options = attr_options + end + + def field_type + @field_type ||= case type + when :integer then :number_field + when :float, :decimal then :text_field + when :time then :time_select + when :datetime, :timestamp then :datetime_select + when :date then :date_select + when :text then :text_area + when :boolean then :check_box + else + :text_field + end + end + + def default + @default ||= case type + when :integer then 1 + when :float then 1.5 + when :decimal then "9.99" + when :datetime, :timestamp, :time then Time.now.to_s(:db) + when :date then Date.today.to_s(:db) + when :string then name == "type" ? "" : "MyString" + when :text then "MyText" + when :boolean then false + when :references, :belongs_to then nil + else + "" + end + end + + def plural_name + name.sub(/_id$/, '').pluralize + end + + def singular_name + name.sub(/_id$/, '').singularize + end + + def human_name + name.humanize + end + + def index_name + @index_name ||= if polymorphic? + %w(id type).map { |t| "#{name}_#{t}" } + else + column_name + end + end + + def column_name + @column_name ||= reference? ? "#{name}_id" : name + end + + def foreign_key? + !!(name =~ /_id$/) + end + + def reference? + self.class.reference?(type) + end + + def polymorphic? + self.attr_options.has_key?(:polymorphic) + end + + def has_index? + @has_index + end + + def has_uniq_index? + @has_uniq_index + end + + def password_digest? + name == 'password' && type == :digest + end + + def inject_options + "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } + end + + def inject_index_options + has_uniq_index? ? ", unique: true" : "" + end + end + end +end |