using ActiveRecord argument in custom generator - ruby-on-rails

i wanna this custom generator named form , generate a model and create its migration file in db/migrate
this is output :
rails g form test name:string
create app/models/name:string.rb
create app/controllers/name:strings_controller.rb
create app/javascript/api/name:string.js
create app/javascript/component/name:strings.vue
create app/javascript/pages/name:string/index.vue
create app/javascript/pages/name:string/layout.vue
create app/javascript/store/actions/name:string.js
create app/javascript/store/getters/name:string.js
create app/javascript/store/modules/name:string.js
create app/javascript/store/mutations/name:string.js
create db/migrate/20200816162324_create_name:strings.rb
and this is my custom generator class :
require 'rails/generators/active_record'
class FormGenerator < ActiveRecord::Generators::Base
source_root File.expand_path('templates', __FILE__)
source_root File.expand_path('templates', __dir__)
argument :model, type: :string
def create_template
template "models/form.template", "app/models/#{model}.rb"
template "controllers/forms_controller.template", "app/controllers/#{model}s_controller.rb"
template "javascript/api/form.template", "app/javascript/api/#{model}.js"
template "javascript/pages/component/forms.template", "app/javascript/component/#{model}s.vue"
template "javascript/pages/form/index.template", "app/javascript/pages/#{model}/index.vue"
template "javascript/pages/form/layout.template", "app/javascript/pages/#{model}/layout.vue"
template "javascript/store/actions/form.template", "app/javascript/store/actions/#{model}.js"
template "javascript/store/getters/form.template", "app/javascript/store/getters/#{model}.js"
template "javascript/store/modules/form.template", "app/javascript/store/modules/#{model}.js"
template "javascript/store/mutations/form.template", "app/javascript/store/mutations/#{model}.js"
migration_template "create_forms.template", "db/migrate/create_#{model}s.rb"
end
as you can see generator uses the column that i gave it to model instead of model itself
template "models/form.template", "app/models/#{model}.rb" //code
rails g form test name:string
create app/models/name:string.rb //output
what should i do to fix that?

From Ruby on Rails Guide, if you want to add custom command line arguments to a custom generator you have to declare it as a class_option. In this case your custom arguments are an array of columns. For example:
class FormGenerator < ActiveRecord::Generators::Base
...
class_option :columns, type: :array, default: [] # Options :type and :default are not required
def create_template
#columns = options[:columns] # You can use this variable inside template
...
end
end
For more information about class_option method click here.

Related

how to generate a migration with custom generator

this is my generator class in lib/genrators/form
class FormGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __FILE__)
source_root File.expand_path('templates', __dir__)
argument :model, type: :string
def create_template
template "models/form.template", "app/models/#{model}.rb"
template "controllers/forms_controller.template", "app/controllers/#{model}s_controller.rb"
template "javascript/api/form.template", "app/javascript/api/#{model}.js"
template "javascript/pages/component/forms.template", "app/javascript/component/#{model}s.vue"
template "javascript/pages/form/index.template", "app/javascript/pages/#{model}/index.vue"
template "javascript/pages/form/layout.template", "app/javascript/pages/#{model}/layout.vue"
template "javascript/store/actions/form.template", "app/javascript/store/actions/#{model}.js"
template "javascript/store/getters/form.template", "app/javascript/store/getters/#{model}.js"
template "javascript/store/modules/form.template", "app/javascript/store/modules/#{model}.js"
template "javascript/store/mutations/form.template", "app/javascript/store/mutations/#{model}.js"
end
end
and this is output :
rails g form test name:string
create app/models/test.rb
create app/controllers/tests_controller.rb
create app/javascript/api/test.js
create app/javascript/component/tests.vue
create app/javascript/pages/test/index.vue
create app/javascript/pages/test/layout.vue
create app/javascript/store/actions/test.js
create app/javascript/store/getters/test.js
create app/javascript/store/modules/test.js
create app/javascript/store/mutations/test.js
i wanna this generator , generates a migration file in db/migrate
i have tried these things and it didnt work out :
class FormGenerator < Rails::Generators::Base
include Rails::Generators::Migration
include ActiveRecord::Generators::Base
migration_template

Using partials when building custom generators

I am building custom generators to generate rails models. The generator can use one of many templates to build one model. Some logic is the same in all templates.
Is it possible to extract some parts of the templates into partials?
Here's an example of what I want to do:
lib/generators/custom_model/custom_model_generator.rb
class CustomModelGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)
argument :model_name, type: :string
argument :model_type, type: :string
...
include GeneratorsHelper
def generate_model
template_path =
case model_type
when 'car' then 'car_model.rb.erb'
when 'plane' then 'plane_model.rb.erb'
...
end
template template_path, "app/models/#{model_name}.rb"
end
end
Here is one template:
lib/generators/custom_model/templates/car_model.rb.erb
class <%= model_name.camelcase %> < ApplicationRecord
def start
puts "Vroum!"
end
end
The #start method will also be used in the other model generators. I would like to extract it it something like a partial. Is that possible?

Prevent custom generator from generating tests

I am learning to write generators. I used Rails' scaffold_controller generator as the starting point.
require 'rails/generators/resource_helpers'
module Rails
module Generators
class ScaffoldControllerGenerator < NamedBase # :nodoc:
include ResourceHelpers
check_class_collision suffix: "Controller"
class_option :helper, type: :boolean
class_option :orm, banner: "NAME", type: :string, required: true,
desc: "ORM to generate the controller for"
argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_controller_files
template "controller.rb", File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
end
#hook_for :template_engine, :test_framework, as: :scaffold
end
end
end
As you can see, I commented out the hook_for, hoping this will not hook up the test framework generators. However when I run this generator, tests are still generated. Plus, I also want to skip jbuilder and helper generation. Here is a list of all things generated:
create app/controllers/books_controller.rb
invoke erb
create app/views/books
create app/views/books/index.html.erb
create app/views/books/edit.html.erb
create app/views/books/show.html.erb
create app/views/books/new.html.erb
create app/views/books/_form.html.erb
invoke test_unit
create test/controllers/books_controller_test.rb
invoke helper
create app/helpers/books_helper.rb
invoke test_unit
invoke jbuilder
create app/views/books/index.json.jbuilder
create app/views/books/show.json.jbuilder
How can I skil generating test/helper/jbuilder by configuring my custom generator?
I realized that I was actually monkey patching the same generator class, so the original setting will still be intact.
I have to remove these hooks manually.
remove_hook_for :jbuilder, :test_framework

Add custom generator in addition to default rails generators

What I need is to add some translations to i18n on scaffold generating. I'd like to know: is there possibility to force rails g scaffold to invoke my own generator in addition to defaults?
If not, how can I invoke default Rails generators (e.g. active_record) in my generator?
Thank you!
According to the doc here, you can use generate from your generator to invoke another generator.
generate a_generator_name, args_as_string
class FooGenerator < Rails::Generators::Base
argument :attributes, :type => :array
def call
do_your_stuff
run_scaffold
end
private
def do_your_stuff
end
def run_scaffold
generate 'scaffold', attributes.join(' ')
end
end

Change argument before passing to hook in rails generator

I'm trying to make simple view generator and using DRY principle, I don't want to have my own html (erb/haml/slim) templates. I'd like my generator to hook to existing template engine and pass it some arguments.
My view_generator.rb file looks like this:
class ViewGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
def some_custom_method
(...)
end
hook_for :template_engine, :as => :scaffold
end
Everything works fine like this. What I'd like to do in my some_custom_method is to add couple of attributes:
def some_custom_method
new_attribute = Rails::Generators::GeneratedAttribute.new("description")
new_attribute.type = :integer
attributes << new_attribute
end
What happens is that I insert new_attribute in attributes array, but when the hook_for is executed, the attribute variable reverts back to original one passed from command line.
How can I bypass this?
At the point some_custom_method is called, attributes are already set (via ARGV) and by checking the code I don't see a clear way to alter them from there. You can use another approach by overriding start class method in your generator and manipulate the args directly, like this:
class ViewGenerator < Rails::Generators::NamedBase
# your code ...
def self.start(args, config)
args.insert(1, 'description:integer') # 0 being the view name
super
end
end

Resources