lib/scaffolding/transformer.rb in bullet_train-super_scaffolding-1.2.10 vs lib/scaffolding/transformer.rb in bullet_train-super_scaffolding-1.2.11

- old
+ new

@@ -21,10 +21,20 @@ def last_joinable_parent "Team" end + def top_level_model? + parent == "Team" || no_parent? + end + + # We write an explicit method here so we know we + # aren't handling `parent` in this situation as `nil`. + def no_parent? + parent == "None" + end + def update_action_models_abstract_class(targets_n) end def initialize(child, parents, cli_options = {}) self.child = child @@ -39,11 +49,13 @@ RUBY_NEW_FIELDS_PROCESSING_HOOK = "# 🚅 super scaffolding will insert processing for new fields above this line." RUBY_NEW_ARRAYS_HOOK = "# 🚅 super scaffolding will insert new arrays above this line." RUBY_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will insert new fields above this line." RUBY_ADDITIONAL_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will also insert new fields above this line." RUBY_EVEN_MORE_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will additionally insert new fields above this line." + RUBY_NEW_API_VERSION_HOOK = "# 🚅 super scaffolding will insert new api versions above this line." RUBY_FILES_HOOK = "# 🚅 super scaffolding will insert file-related logic above this line." + RUBY_FACTORY_SETUP_HOOK = "# 🚅 super scaffolding will insert factory setup in place of this line." ERB_NEW_FIELDS_HOOK = "<%#{RUBY_NEW_FIELDS_HOOK} %>" CONCERNS_HOOK = "# 🚅 add concerns above." ATTR_ACCESSORS_HOOK = "# 🚅 add attribute accessors above." BELONGS_TO_HOOK = "# 🚅 add belongs_to associations above." HAS_MANY_HOOK = "# 🚅 add has_many associations above." @@ -249,15 +261,10 @@ end transformed_file_content.join end - # TODO I was running into an error in a downstream application where it couldn't find silence_logs? We should implement it in this package. - def silence_logs? - ENV["SILENCE_LOGS"].present? - end - def scaffold_file(file, overrides: false) transformed_file_content = get_transformed_file_content(file) transformed_file_name = transform_string(file) # Remove `_overrides` from the file name if we're sourcing from a local override folder. @@ -288,10 +295,13 @@ puts "Proceeding to generate '#{transformed_directory_name}'." end Dir.foreach(resolve_template_path(directory)) do |file| file = "#{directory}/#{file}" + + next if file.match?("/_menu_item.html.erb") && !top_level_model? + unless File.directory?(resolve_template_path(file)) scaffold_file(file) end end @@ -303,10 +313,13 @@ end if override_path Dir.foreach(override_path) do |file| file = "#{directory}_overrides/#{file}" + + next if file.match?("/_menu_item.html.erb") && !top_level_model? + unless File.directory?(resolve_template_path(file)) scaffold_file(file, overrides: true) end end end @@ -569,19 +582,19 @@ end def add_has_many_association has_many_line = ["has_many :completely_concrete_tangible_things"] - # TODO I _think_ this is the right way to check for whether we need `class_name` to specify the name of the model. - unless transform_string("completely_concrete_tangible_things").classify == child + # Specify the class name if the model is namespaced. + if child.match?("::") has_many_line << "class_name: \"Scaffolding::CompletelyConcrete::TangibleThing\"" end has_many_line << "dependent: :destroy" - # TODO I _think_ this is the right way to check for whether we need `foreign_key` to specify the name of the model. - unless transform_string("absolutely_abstract_creative_concept_id") == "#{parent.underscore}_id" + # Specify the foreign key if the parent is namespaced. + if parent.match?("::") has_many_line << "foreign_key: :absolutely_abstract_creative_concept_id" # And if we need `foreign_key`, we should also specify `inverse_of`. has_many_line << "inverse_of: :absolutely_abstract_creative_concept" end @@ -912,11 +925,12 @@ if type == "password_field" field_content.gsub!(/\s%>/, ", options: { password: true } %>") end - scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/show.html.erb", field_content.strip, ERB_NEW_FIELDS_HOOK, prepend: true) + show_page_doesnt_exist = child == "User" + scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/show.html.erb", field_content.strip, ERB_NEW_FIELDS_HOOK, prepend: true, suppress_could_not_find: show_page_doesnt_exist) end # # INDEX TABLE @@ -929,10 +943,24 @@ unless ["Team", "User"].include?(child) scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb", field_content, "<%# 🚅 super scaffolding will insert new field headers above this line. %>", prepend: true) end + # If these strings are the same, we get duplicate variable names in the _index.html.erb partial, + # so we account for that here. Run the Super Scaffolding test setup script and check the index partial + # of models with namespaced parents for reference (i.e. - Objective, Projects::Step). + transformed_abstract_str = transform_string("absolutely_abstract_creative_concept") + transformed_concept_str = transform_string("creative_concept") + transformed_file_name = transform_string("./app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb") + if (transformed_abstract_str == transformed_concept_str) && File.exist?(transformed_file_name) + replace_in_file( + transformed_file_name, + "#{transformed_abstract_str} = @#{transformed_abstract_str} || @#{transformed_concept_str}", + "#{transformed_abstract_str} = @#{transformed_concept_str}" + ) + end + table_cell_options = [] if first_table_cell table_cell_options << "url: [:account, tangible_thing]" end @@ -1391,12 +1419,25 @@ # add user permissions. add_ability_line_to_roles_yml end + # Add factory setup in API controller test. unless cli_options["skip-api"] - scaffold_replace_line_in_file("./test/controllers/api/v1/scaffolding/completely_concrete/tangible_things_controller_test.rb", build_factory_setup.join("\n"), "# 🚅 super scaffolding will insert factory setup in place of this line.") + test_name = transform_string("./test/controllers/api/v1/scaffolding/completely_concrete/tangible_things_controller_test.rb") + test_lines = File.open(test_name).readlines + + # Shift contents of controller test after skipping `unless scaffolding_things_disabled?` block. + class_block_index = Scaffolding::FileManipulator.find(test_lines, "class #{transform_string("Api::V1::Scaffolding::CompletelyConcrete::TangibleThingsControllerTest")}") + new_lines = Scaffolding::BlockManipulator.shift_block(lines: test_lines, block_start: test_lines[class_block_index], shift_contents_only: true) + Scaffolding::FileManipulator.write(test_name, new_lines) + + # Ensure variables built with factories are indented properly. + factory_hook_index = Scaffolding::FileManipulator.find(new_lines, RUBY_FACTORY_SETUP_HOOK) + factory_hook_indentation = Scaffolding::BlockManipulator.indentation_of(factory_hook_index, new_lines) + indented_factory_lines = build_factory_setup.map { |line| "#{factory_hook_indentation}#{line}\n" } + scaffold_replace_line_in_file(test_name, indented_factory_lines.join, new_lines[factory_hook_index]) end # add children to the show page of their parent. unless cli_options["skip-parent"] || parent == "None" scaffold_add_line_to_file( @@ -1488,11 +1529,11 @@ File.write(routes_path, <<~RUBY) collection_actions = [:index, :new, :create] # 🚅 Don't remove this block, it will break Super Scaffolding. - begin do + begin namespace :#{routes_namespace} do shallow do resources :teams do end end @@ -1503,15 +1544,39 @@ retry end begin routes_manipulator.apply([routes_namespace]) - Scaffolding::FileManipulator.write("config/routes.rb", routes_manipulator.lines) + Scaffolding::FileManipulator.write(routes_path, routes_manipulator.lines) rescue => _ add_additional_step :red, "We weren't able to automatically add your `#{routes_namespace}` routes for you. In theory this should be very rare, so if you could reach out on Slack, you could probably provide context that will help us fix whatever the problem was. In the meantime, to add the routes manually, we've got a guide at https://blog.bullettrain.co/nested-namespaced-rails-routing-examples/ ." end + # If we're using a custom namespace, we have to make sure the newly + # scaffolded routes are drawn in the `config/routes.rb` and API routes files. + if cli_options["namespace"] + draw_line = "draw \"#{routes_namespace}\"" + + [ + "config/routes.rb", + "config/routes/api/#{BulletTrain::Api.current_version}.rb" + ].each do |routes_file| + original_lines = File.readlines(routes_file) + + # Define which line we want to place the draw line under in the original routes files. + insert_line = if routes_file.match?("api") + draw_line = " #{draw_line}" # Add necessary indentation. + "namespace :v1 do" + else + "draw \"sidekiq\"" + end + + new_lines = Scaffolding::BlockManipulator.insert(draw_line, lines: original_lines, within: insert_line) + Scaffolding::FileManipulator.write(routes_file, new_lines) + end + end + unless cli_options["skip-api"] begin api_routes_manipulator = Scaffolding::RoutesFileManipulator.new("config/routes/api/#{BulletTrain::Api.current_version}.rb", child, parent, cli_options) api_routes_manipulator.apply([BulletTrain::Api.current_version.to_sym]) Scaffolding::FileManipulator.write("config/routes/api/#{BulletTrain::Api.current_version}.rb", api_routes_manipulator.lines) @@ -1521,10 +1586,10 @@ end end unless cli_options["skip-parent"] - if parent == "Team" || parent == "None" + if top_level_model? icon_name = nil if cli_options["sidebar"].present? icon_name = cli_options["sidebar"] else puts ""