disco-railties/lib/generators/disco/scaffold/scaffold_generator.rb
require 'generators/disco/processor_name.rb'
require 'generators/disco/domain.rb'
module Disco
module Generators
class ScaffoldGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
argument :attributes, type: :array, default: [], banner: 'field[:type] field[:type]'
include ProcessorName
include Domain
ACTIONS = %w(create update delete)
hook_for :model, in: :disco, require: true
hook_for :command, in: :disco, require: true do |hook|
fail 'do not use id as scaffolding attribute! This is reserved for the model id' if attributes_names.include? 'id'
ACTIONS.each do |action|
invoke hook, args_for_command_action(action), opts_for_command_action(action)
add_to_projections(action)
end
end
def add_routes
routing_code = ''
class_path.each_with_index do |namespace, index|
add_line_with_indent routing_code, (index + 1), "namespace :#{namespace} do"
end
add_line_with_indent routing_code, (class_path.length + 1), "resources :#{plural_name}"
class_path.each_with_index do |_, index|
add_line_with_indent routing_code, (class_path.length - index), 'end'
end
route routing_code[2..-1]
end
hook_for :scaffold_controller, in: :disco, require: true do |hook|
invoke hook
add_event_source_to_views
end
protected
def args_for_command_action(action)
args = [command_name_for_action(action)]
args << 'id' unless action == 'create'
args += attributes_names unless action == 'delete'
args
end
def opts_for_command_action(action)
opts = ["--event=#{event_name_for_action(action)}"]
opts << "--processor=#{processor_name}" unless skip_processor?
opts << "--model_name=#{class_name}"
opts << '--unique_id' if action == 'create'
opts << '--persisted' if action == 'update'
opts << '--skip_model' if action == 'delete'
opts
end
def add_event_source_to_views
return if behavior == :revoke
include_text = "<%= event_source('#{class_name}Projection') %>\n"
prepend_to_file File.join('app/views', class_path, plural_file_name, 'index.html.erb'), include_text
prepend_to_file File.join('app/views', class_path, plural_file_name, 'show.html.erb'), include_text
end
def add_to_projections(action)
return if behavior == :revoke
content = "\n
def #{projection_name_for_action(action)}(event)
#{projection_body_for_action(action)}
end"
indent(content) if namespaced?
inject_into_file File.join('app/projections', class_path, "#{file_name}_projection.rb"), content,
after: /(\s)*include(\s)*ActiveProjection::ProjectionType/
end
def command_name_for_action(action)
(class_path + ["#{action}_#{file_name}"]) * '/'
end
def event_name_for_action(action)
(class_path + ["#{action}d_#{file_name}"]) * '/'
end
def projection_name_for_action(action)
(event_name_for_action(action) + '_event').gsub('/', '__')
end
def projection_body_for_action(action)
case action
when 'create'
"#{class_name}.create! event.to_hash"
when 'update'
"#{class_name}.find(event.id).update! event.values"
when 'delete'
"#{class_name}.find(event.id).destroy!"
else
fail 'unknown action'
end
end
def add_line_with_indent(target, indent, str)
target << "#{' ' * indent}#{str}\n"
end
end
end
end