Skip to content

Instantly share code, notes, and snippets.

@Sylvance
Created May 20, 2021 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sylvance/52437e707d6ab0e68e3a0be2d855ec96 to your computer and use it in GitHub Desktop.
Save Sylvance/52437e707d6ab0e68e3a0be2d855ec96 to your computer and use it in GitHub Desktop.
MMVCR_Generator
<%= form_with(model: {ModelSingular}, class: "min-w-max w-full") do |form| %>
<% if {ModelSingular}.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize({ModelSingular}.errors.count, "error") %> prohibited this {ModelSingular} from being saved:</h2>
<ul>
<% {ModelSingular}.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div>
<div class="bg-gray-200 text-gray-600 text-sm leading-normal">
<p class="py-3 px-6 text-left font-bold uppercase">{ModelSingularCamelize} Form</p>
</div>
</div>
<div class="text-gray-600 text-sm font-light">
<div class="border-b border-gray-200">
<div class="flex">
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param1}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param1_type} :{param1}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param1_titlize}" %>
</div>
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param2}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param2_type} :{param2}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param2_titlize}" %>
</div>
</div>
<div class="flex">
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param3}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param3_type} :{param3}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param3_titlize}" %>
</div>
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param4}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param4_type} :{param4}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param4_titlize}" %>
</div>
</div>
<div class="flex">
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param5}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param5_type} :{param5}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param5_titlize}" %>
</div>
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param6}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param6_type} :{param6}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param6_titlize}" %>
</div>
</div>
<div class="flex">
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param7}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param7_type} :{param7}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param7_titlize}" %>
</div>
<div class="md:w-1/2 py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param8}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.{param8_type} :{param8}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker", placeholder: "{param8_titlize}" %>
</div>
</div>
<div class="py-3 px-6 text-left whitespace-nowrap">
<%= form.label :{param9}, class: "block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2" %>
<%= form.select :{param9}, {enum_class}, class: "appearance-none border rounded w-full py-2 px-3 text-grey-darker"%>
</div>
<%= form.submit class: "py-3 px-6 mx-6 my-3 text-white bg-purple-700 rounded-md focus:bg-purple-800 focus:outline-none" %>
</div>
</div>
<% end %>
json.extract! {ModelSingular}, :id, {model_params}, :created_at, :updated_at
json.url {ModelSingular}_url({ModelSingular}, format: :json)
class Create{ModelPluralCamelize} < ActiveRecord::Migration[6.1]
def change
create_table :{ModelPlural}, id: :uuid do |t|
{ModelFields}
t.timestamps
end
{ModelIndexes}
{ModelReferences}
end
end
<div class="flex items-center justify-center font-sans">
<div class="w-full">
<header class="flex items-center justify-between">
<h2 class="text-lg leading-6 font-medium text-purple-600">{plural_name_camelize} / <%= @{ModelSingular}.{ref_name} || 'Edit {ModelSingularCamelize}' %> </h2>
<%= link_to {plural_name}_path, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
<span class="sr-only">Back</span>
<!-- Heroicon name: solid/chevron-left -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
Back
<% end %>
</header>
<div class="bg-white shadow-md rounded mt-6">
<%= render 'form', {ModelSingular}: @{ModelSingular} %>
</div>
</div>
</div>
<p id="notice"><%= notice %></p>
<%# https://tailwindcomponents.com/component/projects-table %>
<div class="flex items-center justify-center font-sans">
<div class="w-full">
<header class="flex items-center justify-between">
<h2 class="text-lg leading-6 font-medium text-purple-600">{plural_name_camelize} <%= "/ Search results" if @search_value.present? %></h2>
<%= form_with(url: {plural_name}_path, method: :get, class: 'flex') do |form| %>
<%= form.search_field :search, class: "appearance-none border rounded py-2 px-3 text-grey-darker", placeholder: "Search {plural_name_camelize}" %>
<%= form.submit "Search", class: "ml-3 py-3 px-6 text-white bg-purple-700 rounded-md focus:bg-purple-800 focus:outline-none" %>
<% end %>
<%= link_to new_{ModelSingular}_path, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
<svg class="mr-2" width="12" height="20" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 5a1 1 0 011 1v3h3a1 1 0 110 2H7v3a1 1 0 11-2 0v-3H2a1 1 0 110-2h3V6a1 1 0 011-1z"/>
</svg>
New {ModelSingularCamelize}
<% end %>
</header>
<div class="bg-white shadow-md rounded mt-6">
<table class="min-w-max w-full table-auto">
<thead>
<tr class="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
<th class="py-3 px-6 text-left">Name</th>
<th class="py-3 px-6 text-left">Email</th>
<th class="py-3 px-6 text-center">Role</th>
<th class="py-3 px-6 text-center">Settings</th>
<th class="py-3 px-6 text-center">Actions</th>
</tr>
</thead>
<tbody class="text-gray-600 text-sm font-light">
<% @{plural_name}.each do |{ModelSingular}| %>
<tr class="border-b border-gray-200 hover:bg-gray-100">
<td class="py-3 px-6 text-left whitespace-nowrap">
<div class="flex items-center">
<div class="mr-2">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="24" height="24"
viewBox="0 0 48 48"
style=" fill:#000000;">
<path fill="#80deea" d="M24,34C11.1,34,1,29.6,1,24c0-5.6,10.1-10,23-10c12.9,0,23,4.4,23,10C47,29.6,36.9,34,24,34z M24,16 c-12.6,0-21,4.1-21,8c0,3.9,8.4,8,21,8s21-4.1,21-8C45,20.1,36.6,16,24,16z"></path><path fill="#80deea" d="M15.1,44.6c-1,0-1.8-0.2-2.6-0.7C7.6,41.1,8.9,30.2,15.3,19l0,0c3-5.2,6.7-9.6,10.3-12.4c3.9-3,7.4-3.9,9.8-2.5 c2.5,1.4,3.4,4.9,2.8,9.8c-0.6,4.6-2.6,10-5.6,15.2c-3,5.2-6.7,9.6-10.3,12.4C19.7,43.5,17.2,44.6,15.1,44.6z M32.9,5.4 c-1.6,0-3.7,0.9-6,2.7c-3.4,2.7-6.9,6.9-9.8,11.9l0,0c-6.3,10.9-6.9,20.3-3.6,22.2c1.7,1,4.5,0.1,7.6-2.3c3.4-2.7,6.9-6.9,9.8-11.9 c2.9-5,4.8-10.1,5.4-14.4c0.5-4-0.1-6.8-1.8-7.8C34,5.6,33.5,5.4,32.9,5.4z"></path><path fill="#80deea" d="M33,44.6c-5,0-12.2-6.1-17.6-15.6C8.9,17.8,7.6,6.9,12.5,4.1l0,0C17.4,1.3,26.2,7.8,32.7,19 c3,5.2,5,10.6,5.6,15.2c0.7,4.9-0.3,8.3-2.8,9.8C34.7,44.4,33.9,44.6,33,44.6z M13.5,5.8c-3.3,1.9-2.7,11.3,3.6,22.2 c6.3,10.9,14.1,16.1,17.4,14.2c1.7-1,2.3-3.8,1.8-7.8c-0.6-4.3-2.5-9.4-5.4-14.4C24.6,9.1,16.8,3.9,13.5,5.8L13.5,5.8z"></path><circle cx="24" cy="24" r="4" fill="#80deea"></circle>
</svg>
</div>
<span class="font-medium"><%= {ModelSingular}.name %></span>
</div>
</td>
<td class="py-3 px-6 text-left truncate">
<div class="flex items-center">
<span><%= {ModelSingular}.email %></span>
</div>
</td>
<td class="py-3 px-6 text-center">
<span class="<%= class_roles({ModelSingular}.role) %>">
<%= {ModelSingular}.role %>
</span>
</td>
<td class="py-3 px-6 text-left whitespace-nowrap">
<div class="flex items-center justify-center">
<img class="w-6 h-6 rounded-full border-gray-200 border transform hover:scale-125" src="https://randomuser.me/api/portraits/men/1.jpg"/>
<img class="w-6 h-6 rounded-full border-gray-200 border -m-1 transform hover:scale-125" src="https://randomuser.me/api/portraits/women/2.jpg"/>
<img class="w-6 h-6 rounded-full border-gray-200 border -m-1 transform hover:scale-125" src="https://randomuser.me/api/portraits/men/3.jpg"/>
</div>
</td>
<td class="py-3 px-6 text-center">
<div class="flex item-center justify-center">
<%= link_to {ModelSingular}, class: "w-4 mr-2 transform hover:text-purple-500 hover:scale-110" do %>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
<% end %>
<%= link_to edit_{ModelSingular}_path({ModelSingular}), class: "w-4 mr-2 transform hover:text-purple-500 hover:scale-110" do %>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
<% end %>
<%= link_to {ModelSingular}, method: :delete, data: { confirm: 'Are you sure?' }, class: "w-4 mr-2 transform hover:text-purple-500 hover:scale-110" do %>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
</svg>
<% end %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
<div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
<div class="flex-1 flex justify-between sm:hidden">
<a href="#" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500">
Previous
</a>
<a href="#" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500">
Next
</a>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
<%= link_to {plural_name}_path(page_num: @pagy.prev || @pagy.page, search: @search_value), class: "relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-25", disabled: @pagy.prev.nil? do %>
<span class="sr-only">Previous</span>
<!-- Heroicon name: solid/chevron-left -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
<% end %>
<% @pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
<% if item.is_a?(Integer) -%>
<%= link_to item.to_s, {plural_name}_path(page_num: item, search: @search_value), class: "relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" %>
<% elsif item.is_a?(String) -%>
<%= link_to item, {plural_name}_path(page_num: item.to_i, search: @search_value), class: "relative inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-purple-600 hover:bg-purple-700" %>
<% elsif item == :gap -%>
<span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700">
...
</span>
<% end -%>
<% end -%>
<%= link_to {plural_name}_path(page_num: @pagy.next || @pagy.page, search: @search_value), class: "relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-25", disabled: @pagy.next.nil? do %>
<span class="sr-only">Next</span>
<!-- Heroicon name: solid/chevron-right -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
</svg>
<% end %>
</nav>
</div>
</div>
<div>
<% if @search_value.present? %>
<%= link_to {plural_name}_path, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
<< Back
<% end %>
<% end %>
</div>
</div>
</div>
</div>
</div>
json.array! @{plural_name}, partial: "{plural_name}/{ModelSingular}", as: :{ModelSingular}
class MMVCRGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
class_option :search_fields, type: :string, default: 'name, id'
def create_model_file
timestamp = Time.now.strftime("%Y%m%d%H%M%S")
built_model = build_model_from_json
copy_file "models/model.rb", "app/models/#{plural_name.singularize}.rb"
gsub_file "app/models/#{plural_name.singularize}.rb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
end
def create_migration_file
timestamp = Time.now.strftime("%Y%m%d%H%M%S")
built_model = build_model_from_json
copy_file "migrations/create_models.rb", "db/migrate/#{timestamp}_create_#{plural_name}.rb"
gsub_file "db/migrate/#{timestamp}_create_#{plural_name}.rb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "db/migrate/#{timestamp}_create_#{plural_name}.rb", "{ModelPlural}", "#{plural_name}"
gsub_file "db/migrate/#{timestamp}_create_#{plural_name}.rb", "{ModelFields}", "#{built_model[0].join("\n")}"
gsub_file "db/migrate/#{timestamp}_create_#{plural_name}.rb", "{ModelIndexes}", "#{built_model[1].join("\n")}"
gsub_file "db/migrate/#{timestamp}_create_#{plural_name}.rb", "{ModelReferences}", "#{built_model[2].join("\n")}"
end
def create_peparizer_search_file
copy_file "services/search/models.rb", "app/services/search/#{file_name}.rb"
gsub_file "app/services/search/#{file_name}.rb", "{ModelPlural}", "#{plural_name.camelize}"
gsub_file "app/services/search/#{file_name}.rb", "{ModelSingular}", "#{plural_name.camelize.singularize}"
gsub_file "app/services/search/#{file_name}.rb", "{value1}", "#{options['search_fields'].split(',').first}"
gsub_file "app/services/search/#{file_name}.rb", "{value2}", "#{options['search_fields'].split(',').second}"
end
def create_peparizer_controller_file
copy_file "controllers/models_controller.rb", "app/controllers/#{file_name}_controller.rb"
gsub_file "app/controllers/#{file_name}_controller.rb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/controllers/#{file_name}_controller.rb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/controllers/#{file_name}_controller.rb", "{ModelSingularCamelize}", "#{plural_name.camelize.singularize}"
gsub_file "app/controllers/#{file_name}_controller.rb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/controllers/#{file_name}_controller.rb", "{ModelParams}", "#{options['params']}"
end
def create_views_files
copy_file "views/models/_form.html.erb", "app/views/#{file_name}/_form.html.erb"
copy_file "views/models/_user.json.jbuilder", "app/views/#{file_name}/_#{file_name.singularize}.json.jbuilder"
copy_file "views/models/edit.html.erb", "app/views/#{file_name}/edit.html.erb"
copy_file "views/models/index.html.erb", "app/views/#{file_name}/index.html.erb"
copy_file "views/models/index.json.jbuilder", "app/views/#{file_name}/index.json.jbuilder"
copy_file "views/models/new.html.erb", "app/views/#{file_name}/new.html.erb"
copy_file "views/models/show.html.erb", "app/views/#{file_name}/show.html.erb"
copy_file "views/models/show.json.jbuilder", "app/views/#{file_name}/show.json.jbuilder"
gsub_file "app/views/#{file_name}/_form.html.erb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/_#{file_name.singularize}.json.jbuilder", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/edit.html.erb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/index.html.erb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/index.json.jbuilder", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/new.html.erb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/show.html.erb", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/show.json.jbuilder", "{ModelPlural}", "#{plural_name}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/_#{file_name.singularize}.json.jbuilder", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/edit.html.erb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/index.html.erb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/index.json.jbuilder", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/new.html.erb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/show.html.erb", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/show.json.jbuilder", "{ModelPluralCamelize}", "#{plural_name.camelize}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/_#{file_name.singularize}.json.jbuilder", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/edit.html.erb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/index.html.erb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/index.json.jbuilder", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/new.html.erb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/show.html.erb", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/show.json.jbuilder", "{ModelSingular}", "#{plural_name.singularize}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/_#{file_name.singularize}.json.jbuilder", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/edit.html.erb", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/index.html.erb", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/index.json.jbuilder", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/new.html.erb", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/show.html.erb", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
gsub_file "app/views/#{file_name}/show.json.jbuilder", "{ModelSingularCamelize}", "#{plural_name.singularize.camelize}"
end
def create_form_file_params
gsub_file "app/views/#{file_name}/_form.html.erb", "{param1}", "#{form_params[0][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param2}", "#{form_params[1][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param3}", "#{form_params[2][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param4}", "#{form_params[3][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param5}", "#{form_params[4][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param6}", "#{form_params[5][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param7}", "#{form_params[6][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param8}", "#{form_params[7][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param9}", "#{form_params[8][:param]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param1_type}", "#{form_params[0][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param2_type}", "#{form_params[1][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param3_type}", "#{form_params[2][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param4_type}", "#{form_params[3][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param5_type}", "#{form_params[4][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param6_type}", "#{form_params[5][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param7_type}", "#{form_params[6][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param8_type}", "#{form_params[7][:param_type]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param1_titlize}", "#{form_params[0][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param2_titlize}", "#{form_params[1][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param3_titlize}", "#{form_params[2][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param4_titlize}", "#{form_params[3][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param5_titlize}", "#{form_params[4][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param6_titlize}", "#{form_params[5][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param7_titlize}", "#{form_params[6][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{param8_titlize}", "#{form_params[7][:param_titlize]}"
gsub_file "app/views/#{file_name}/_form.html.erb", "{enum_class}", "#{enum_class}"
end
private
def build_model_from_json
fields = []
idxs = []
refs = []
model_name = plural_name.singularize
hash.each do |key, value|
next if key == :_refs || key == :_idxs
fields.append("t.#{value[:type]} :#{key}, #{aux_field(value.except(:type))}")
end
hash[:_idxs].each do |idxs_hash|
idxs.append("add_index :#{plural_name}, :#{idxs_hash[:field]}, #{aux_field(idxs_hash.except(:field))}")
end
hash[:_refs].each do |refs_hash|
refs.append("add_reference :#{plural_name}, :#{refs_hash[:field]}, #{aux_field(refs_hash.except(:field))}")
end
return [fields, idxs, refs]
end
def aux_field(field)
field_str = field.map do |key, value|
"#{key}:#{value}" unless value.nil?
end
return field_str.join(', ')[0...-2] if field_str.size > 1
field_str
end
def enum_class
User::ROLES.keys
end
def form_params
[
{
key: 1,
param: 'name',
param_type: 'text_field',
param_titlize: 'Name'
},
{
key: 2,
param: 'first_name',
param_type: 'text_field',
param_titlize: 'First Name'
},
{
key: 3,
param: 'last_name',
param_type: 'text_field',
param_titlize: 'Last Name'
},
{
key: 4,
param: 'email',
param_type: 'email_field',
param_titlize: 'Name'
},
{
key: 5,
param: 'password',
param_type: 'password_field',
param_titlize: 'Password'
},
{
key: 6,
param: 'password_confirmation',
param_type: 'password_field',
param_titlize: 'Password confirmation'
},
{
key: 7,
param: 'phone_number',
param_type: 'telephone_field',
param_titlize: 'Phone number'
},
{
key: 8,
param: 'address',
param_type: 'text_area',
param_titlize: 'Address'
},
{
key: 9,
param: 'role'
}
]
end
def hash
{
name: {
type: 'string',
null: false
},
first_name: {
type: 'string',
null: false
},
last_name: {
type: 'string',
null: false
},
email: {
type: 'string',
null: false
},
password: {
type: 'string',
null: false
},
password_confirmation: {
type: 'string',
null: false
},
phone_number: {
type: 'string',
null: false
},
address: {
type: 'text',
null: false
},
role: {
type: 'integer',
null: false,
default: 0
},
settings: {
type: 'hstore',
null: false,
default: {}
},
_idxs: [
{
field: 'name',
unique: true
},
{
field: 'email',
unique: true
}
],
_refs: []
}
end
end
class {ModelPluralCamelize}Controller < ApplicationController
before_action :set_{ModelSingular}, only: %i[ show edit update destroy ]
# GET /{ModelPlural} or /{ModelPlural}.json
def index
{ModelPlural} ||= Search::{ModelPluralCamelize}.new(params).find
@search_value = params[:search] if params.has_key?(:search)
@pagy, @{ModelPlural} = pagy({ModelPlural}, items: 10)
end
# GET /{ModelPlural}/1 or /{ModelPlural}/1.json
def show
end
# GET /{ModelPlural}/new
def new
@{ModelSingular} = {ModelSingularCamelize}.new
end
# GET /{ModelPlural}/1/edit
def edit
end
# POST /{ModelPlural} or /{ModelPlural}.json
def create
@{ModelSingular} = {ModelSingularCamelize}.new({ModelSingular}_params)
respond_to do |format|
if @{ModelSingular}.save
format.html { redirect_to @{ModelSingular}, notice: "{ModelSingularCamelize} was successfully created." }
format.json { render :show, status: :created, location: @{ModelSingular} }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @{ModelSingular}.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /{ModelPlural}/1 or /{ModelPlural}/1.json
def update
respond_to do |format|
if @{ModelSingular}.update({ModelSingular}_params)
format.html { redirect_to @{ModelSingular}, notice: "{ModelSingularCamelize} was successfully updated." }
format.json { render :show, status: :ok, location: @{ModelSingular} }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @{ModelSingular}.errors, status: :unprocessable_entity }
end
end
end
# DELETE /{ModelPlural}/1 or /{ModelPlural}/1.json
def destroy
@{ModelSingular}.destroy
respond_to do |format|
format.html { redirect_to {ModelPlural}_url, notice: "{ModelSingularCamelize} was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_{ModelSingular}
@{ModelSingular} = {ModelSingularCamelize}.find(params[:id])
end
# Only allow a list of trusted parameters through.
def {ModelSingular}_params
params.require(:{ModelSingular}).permit({ModelParams})
end
end
<div class="flex items-center justify-center font-sans">
<div class="w-full">
<header class="flex items-center justify-between">
<h2 class="text-lg leading-6 font-medium text-purple-600">{plural_name_camelize} / <%= @{ModelSingular}.{ref_name_1} || 'New {ModelSingularCamelize}' %> </h2>
<%= link_to {plural_name}_path, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
<span class="sr-only">Back</span>
<!-- Heroicon name: solid/chevron-left -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
Back
<% end %>
</header>
<div class="bg-white shadow-md rounded mt-6">
<%= render 'form', {ModelSingular}: @{ModelSingular} %>
</div>
</div>
</div>
module Search
class {ModelPlural}
def initialize(params)
@params = params
@{value1} = {ModelSingular}.arel_table[:{value1}]
@{value2} = {ModelSingular}.arel_table[:{value2}]
end
def find
if(@params.has_key?(:search))
{ModelSingular}.where(@{value2}.matches("%#{@params[:search]}%"))
.or({ModelSingular}.where(@{value1}.matches("%#{@params[:search]}%")))
else
{ModelSingular}.all
end
end
end
end
<p id="notice"><%= notice %></p>
<div class="flex items-center justify-center font-sans">
<div class="w-full">
<header class="flex items-center justify-between">
<h2 class="text-lg leading-6 font-medium text-purple-600">{plural_name_camelize} / <%= @{ModelSingular}.name %></h2>
<div class="flex">
<%= link_to edit_{ModelSingular}_path(@{ModelSingular}), class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
Edit {ModelSingular}
<% end %>
<%= link_to {plural_name}_path, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" do %>
Back to all {plural_name}
<% end %>
</div>
</header>
<div class="bg-white shadow-md rounded mt-6">
<div class="min-w-max w-full table-auto">
<div>
<div class="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
<div class="py-3 px-6 text-left"><%= @{ModelSingular}.name %></div>
</div>
</div>
<div class="text-gray-600 text-sm font-light">
<div class="border-b border-gray-200">
<div class="flex p-1">
<div class="flex-none w-44 relative">
<%= image_tag("undraw_unicorn_dp2f.svg", alt: "", class: "absolute inset-0 w-full h-full object-cover") %>
</div>
<form class="flex-auto py-7 px-8">
<div class="flex flex-wrap items-baseline">
<h1 class="w-full flex-none text-3xl text-black mb-1.5">
<%= @{ModelSingular}.{ref_name_1} %>
</h1>
<div class="text-lg leading-6 text-black">
<%= @{ModelSingular}.{ref_name_2} %>
</div>
<div class="text-sm text-gray-500 ml-3">
<%= @{ModelSingular}.{ref_name_3} %>
</div>
</div>
<div class="flex space-x-3 mt-3 mb-3 text-sm font-semibold uppercase">
<div class="flex-auto flex space-x-3">
<button class="w-1/2 flex items-center justify-center bg-purple-700 text-white" type="submit">Buy now</button>
<button class="w-1/2 flex items-center justify-center border border-purple-200" type="button">Add to bag</button>
</div>
<button class="flex-none flex items-center justify-center w-12 h-12 text-purple-900 border border-purple-200" type="button" aria-label="like">
<svg width="20" height="20" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" />
</svg>
</button>
</div>
<p class="text-sm text-purple-500">
{ModelSingularCamelize} can create children.
</p>
</form>
</div>
</div>
<section class="px-4 sm:px-6 lg:px-4 xl:px-6 pt-4 pb-4 sm:pb-6 lg:pb-4 xl:pb-6 space-y-4">
<header class="flex items-center justify-between">
<h2 class="text-lg leading-6 font-medium text-black">{child_name_pluralize_camelize}</h2>
<%= link_to new_{child_name}_path({{ModelSingular}_id: @{ModelSingular}.id}), class: "hover:bg-purple-200 hover:text-purple-800 group flex items-center rounded-md bg-purple-100 text-purple-600 text-sm font-medium px-4 py-2" do %>
<svg class="group-hover:text-purple-600 text-purple-500 mr-2" width="12" height="20" fill="currentColor">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 5a1 1 0 011 1v3h3a1 1 0 110 2H7v3a1 1 0 11-2 0v-3H2a1 1 0 110-2h3V6a1 1 0 011-1z"/>
</svg>
Create New {child_name_camelize}
<% end %>
</header>
<ul class="flex">
<% @{ModelSingular}.{child_name}.each do |{child_name}| %>
<%= link_to {child_name} do %>
<li class="ml-2 hover:bg-purple-500 hover:border-transparent hover:shadow-lg hover:text-white group rounded-lg p-4 border border-gray-200 cursor-pointer">
<p class="group-hover:text-white leading-6 font-medium text-black"><%= {child_name}.{child_ref_name_1} %></p>
<p class="text-sm font-medium sm:mb-4 lg:mb-0 xl:mb-4"><%= {child_name}.{child_ref_name_2} %></p>
<li>
<% end %>
<% end %>
</ul>
</section>
</div>
</div>
<div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
<div>
<%= link_to 'Settings', @{ModelSingular}, class: "group flex items-center rounded-md text-sm font-medium hover:underline hover:text-purple-600 px-4 py-2" %>
</div>
</div>
</div>
</div>
</div>
json.partial! "{plural_name}/{ModelSingular}", {ModelSingular}: @{ModelSingular}
Description:
Generator for Model, Migration, View, Controller and Relationships.
Example:
bin/rails generate peparizer some_model_in_plural [options]
--search_fields ':field1, :field2' # only two fields
This will create:
search service
controller
model
views
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment