rails g task folder1/namespace1 task1
Above command will create the task1.rake inside lib/tasks/task1.rake
But, I need to keep my task1.rake inside lib/tasks/folder1/task1.rake
The rails g task generator does not work this way.
Here are the code for the TaskGenerator class
module Rails
module Generators
class TaskGenerator < NamedBase # :nodoc:
argument :actions, type: :array, default: [], banner: "action action"
def create_task_files
template 'task.rb', File.join('lib/tasks', "#{file_name}.rake")
end
end
end
end
As you see the lib/tasks path is hardcoded and you can not pass in options to alter the path.
I think this might be a great addition to the TaskGenerator class.
The answer to your question is that you have to make the folders manually.
Related
If I have a ruby script at the root directory of rails application and I need to access existing Activerecord model which is created inside rails environment. How can I use something like
user = User.new
in my script without establishing a new connection or create a new class.
There are two common ways to deal with Rails models from the command line:
1) rake tasks
Create a rake task in lib/tasks
# example lib/tasks/foo.rake
desc 'an example task'
task :foo => [:environment] do
user = User.new
...
end
And call that task from your command line with:
rake foo
2) script runner
Create a method within your application that does the job
# example in app/models/user.rb
class User < ActiveRecord::Base
...
def self.foo
user = User.new
...
end
end
And call this method from the command line with:
rails runner "User.foo"
I prefer the second way, because it is easier to test and reuse the code.
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
I have a simple rails install generator for an engine I'm making:
module Bouncer
module Generators
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path("../../templates", __FILE__)
desc "Copies locale file and migrations to your application."
def copy_locale
copy_file "../../../config/locales/en.yml", "config/locales/bouncer.en.yml"
end
def copy_migrations
# I would like to run "rake bouncer_engine:install:migrations" right here
# rather than copy_file "../../../db/migrate/blah.rb", "db/migrate/blah.rb"
end
end
end
end
When a user runs rails g bouncer:install, a locale file is copied into their app. I also want to copy in my migrations, but rather than use copy_file method, I was hoping I could just run rake bouncer_engine:install:migrations inside the generator, like I would do from the command line. How can I do this?
The correct way to do this:
#!/usr/bin/env rake
module Bouncer
module Generators
class InstallGenerator < Rails::Generators::Base
desc "Copies migrations to your application."
def copy_migrations
rake("bouncer_engine:install:migrations")
end
end
end
end
This saves a lot of hassle and even takes care of the making sure each migration's name is timestamped properly.
Well, I think it should be possible by just executing the shell command. Here are 6 different ways to execute a shell command in ruby.
But my other suggestion would be instead of implementing it as a rake task, to direcly implement it as part of your generator... I don't know what your exact demands are, but given your description it seems to me that the migrations-task only runs once, when you execute the install task? Or is there a special need to offer it as a rake task as well?
I'm writing a Rails 3.1 engine and testing with RSpec 2. When I use rails generate, I get spec files generated for me automatically, which is so convenient:
$ rails g model Foo
invoke active_record
create db/migrate/20111102042931_create_myengine_foos.rb
create app/models/myengine/foo.rb
invoke rspec
create spec/models/myengine/foo_spec.rb
However, to make the generated specs play nicely with my isolated namespace, I have to wrap the spec each time manually in a module:
require 'spec_helper'
module MyEngine
describe Foo do
it "should be round"
...
end
end
I would love to know if there's a clean and easy way to modify the automatically generated spec 'templates' so that I don't have to wrap the spec in Module MyEngine each time I generate a new model or controller.
You can copy RSpec's templates using a Rake task like:
namespace :spec do
namespace :templates do
# desc "Copy all the templates from rspec to the application directory for customization. Already existing local copies will be overwritten"
task :copy do
generators_lib = File.join(Gem.loaded_specs["rspec-rails"].full_gem_path, "lib/generators")
project_templates = "#{Rails.root}/lib/templates"
default_templates = { "rspec" => %w{controller helper integration mailer model observer scaffold view} }
default_templates.each do |type, names|
local_template_type_dir = File.join(project_templates, type)
FileUtils.mkdir_p local_template_type_dir
names.each do |name|
dst_name = File.join(local_template_type_dir, name)
src_name = File.join(generators_lib, type, name, "templates")
FileUtils.cp_r src_name, dst_name
end
end
end
end
end
Then you can modify the code in #{Rails.root}/lib/templates/rspec/model/model_spec.rb to include the module name.
Copy the '/lib/generators/rspec/scaffold/templates/controller_spec.rb' file from the rspec-rails gem to your 'app/lib/templates/rspec/scaffold' folder, then customize it. Obviously, if you move to a new version of rspec-rails you will want to make sure that your customized template hasn't gotten stale.
I have a number of parsers I run with rakes in a project I'm working on. When using a method name that already exists in another rake, and because they both use the same environment, I get a conflict.
Is there a way to limit the scope of rake files within their namespace? I thought that was the whole point of the namespace?
Example:
namespace :test do
task :test_task => :environment do
...
end
def test_method(argument)
...
end
end
namespace :other_test do
task :test_task => :environment do
...
end
def test_method(argument, argument2)
...
end
end
In this case, when running rake test:test_task I'll receive an invalid amount of arguments error. On the other hand, if I define the method within the task itself, I have to keep the method at the top of the rake file in order. This gets kind of confusing and ugly.
Is that just a necessary evil?
Thanks!
I see the namespaces for rake tasks as serving the same purpose as directories in a file system: they're about organization rather than encapsulation. That's why database tasks are in db:, Rails tasks in rails:, etc.
Rake namespaces are not classes so you need to ask yourself what class you're adding test_method to when you define it within a Rake namespace. The answer is Object. So, when you hit your second task, Object already has a test_method method that takes one parameter and Ruby rightly complains.
The best solution is to make your Rake tasks very thin (just like controllers) and put any supporting methods (such as test_method) off in some library file somewhere sensible. A Rake task should usually just do a bit of set up and then call a library method to do the real work (i.e. the same general layout as a controller).
Executive summary: put all the real work and heavy lifting somewhere in your library files and make your Rake tasks thin wrappers for your libraries. This should make your problem go away through proper code organization.
module Anonymous
namespace :test do
# brabra
end
end
self.class.send(:remove_const, :Anonymous)
module Anonymous
namespace :another_test do
# brabra
end
end
self.class.send(:remove_const, :Anonymous)
Module.new do end block needs you self:: before any definition. To avoid this, you need to name the module and remove it.
I've figured out a way to namespace the methods in Rake tasks so same-named methods don't collide.
Wrap each outer namespace in a uniquely-named module.
extend Rake::DSL
Change your methods to class methods (with self.).
I've tested this, and it still allows one rake task to invoke or depend on another rake task that is in a different module.
Example:
module Test
extend Rake::DSL
namespace :test do
task :test_task => :environment do
...
end
def self.test_method(argument)
...
end
end
end
module OtherTest
extend Rake::DSL
namespace :other_test do
task :test_task => :environment do
...
end
def self.test_method(argument, argument2)
...
end
end
end