Rails 3 Generator custom templates with Engine - ruby-on-rails

When using the rails generators with an Rails::Engine, it does not seem to pick up any template files that are put into the lib dir. As instructed here
http://guides.rubyonrails.org/generators.html#customizing-your-workflow-by-changing-generators-templates
Right now I have
lib/templates/rails/scaffold_controller
I have also tried
lib/my_engine/templates/rails/scaffold_controller
Has anyone else tried this.

It seems that this is not supported for Engines
In a Rails app the Finisher takes care of adding this to the path
module Rails
class Application
module Finisher
include Initializable
initializer :add_generator_templates do
config.generators.templates.unshift(*paths["lib/templates"].existent)
end
......
So this must be done in the Engine config in order for this to work.
module MyEngine
class Engine < ::Rails::Engine
config.generators.templates.unshift File.expand_path("lib/templates", root)
end
end
Is this a bug or the desired behaviour?

Above answer (by stellard himself) doesn't fix my case in Rails 3.2, but How to override a rails generator template in a gem? fix it. Just pointing out for the person like me.

If you use rails g generator MyGenerator in the root path of an Rails 3.2 engine you'll get something like this:
class MyGenerator < Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
end
which doesnt pollute your Engine class and is much more localized to the generator.

Related

Versioning API Helpers in Ruby on Rails

We have a versioned API that follows all the conventions of Rails API versioning. i.e
module API::V4
class Test < ApiController
end
end
But is there a proper way to version helpers? The current helpers directory looks like something like this:
app
|__helpers
|__helper_a.rb
|__helper_b.rb
and all helpers are defined modules.
Is there a way to do this?
module Helpers::V2
class HelperA
end
end
I tried creating a directory app/helpers/v2/helper_a.rb, adding app/helpers/helpers.rb and defining module Helpers But for some reason rails always fails to see Helpers::V2::HelperA
Rails searches each subdirectory of app starting from the subdirectory. app/models/foo/bar.rb contains Foo::Bar not Models::Foo::Bar. app/controllers/api/v4/test.rb contains Api::V4::Test, not Controllers::Api::V4::Test.
So app/helpers/v2/helper_a.rb contains V2::HelperA.
module V2
module HelperA
end
end
If you want to relate the helper version with your API version, it makes sense to mirror the directory structure.
# app/helpers/api/v2/helper_a.rb
# A helper for API v2.
module Api
module V2
module HelperA
end
end
end
Note that it's Api to follow Rails conventions. The autoloader will map app/helpers/api/v2/helper_a.rb to Api::V2::HelperA. It might work with the Rails 5 autoloader, but not the Rails 6 autoloader.
If we use API::V2::HelperA...
[1] pry(main)> API::V2::HelperA
NameError: uninitialized constant API
Did you mean? Api

How can I extend gem class in Rails 6/Zeitwerk without breaking code reloading?

How do I extend a class that is defined by a gem when I'm using rails 6 / zeitwerk?
I've tried doing it in an initializer using require to load up the class first.
I've tried doing it in an initializer and just referencing the class to let autoloading load it up first.
But both of those approaches break auto-reloading in development mode.
I've tried putting it in lib/ or app/, but that doesn't work because then the class never gets loaded from the gem, since my new file is higher up in the load order.
There is a similar question here, but that one specifically asks how to do this in an initializer. I don't care if it's done in an initializer or not, I just want to figure out how to do it some way.
What is the standard way of doing something like this?
I do have one nasty hack that seems to be working, but I don't like it (update: this doesn't work either. reloading is still broken):
the_gem_root = $LOAD_PATH.grep(/the_gem/).grep(/models/).first
require("#{the_gem_root}/the_gem/some_model")
class SomeModel
def my_extension
...
end
end
I know is late, but this was a real pain and someone could find it helpful, in this example I'll be using a modules folder located on app that will contain custom modules and monkey patches for various gems.
# config/application.rb
...
module MyApp
class Application < Rails::Application
config.load_defaults(6.0)
overrides = "#{Rails.root}/app/overrides"
Rails.autoloaders.main.ignore(overrides)
config.to_prepare do
Dir.glob("#{overrides}/**/*_override.rb").each do |override|
load override
end
end
end
end
Apparently this pattern is called the Override pattern, it will prevent the autoload of your overrides by zeitwerk and each file would be loaded manually at the end of the load.
This pattern is also documented in the Ruby on Rails guide: https://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers

Rails modules as strict namespaces

I'm quite new to rails and I'm a bit confused of how modules work here. I have a project structure like this:
# app/models/foo.rb
class Foo < ActiveRecord
# lib/external_service/foo.rb
module ExternalService
class Foo
# lib/external_service/bar.rb
module ExternalService
class Bar
attribute :foo, Foo # not the model
I have worked with many coding languages before and I expected it to be easily possible to use 'Foo' inside Bar and ExternalService just like that but
LoadError: Unable to autoload constant Foo, expected lib/external_service/foo.rb to define it
The ExternalService::Foo should normally not even be visible outside of ExternalService but the whole project dies on this thing
Am I just missing a kinda 'strict mode'-notation or anything to make sure that I obviously mean ExternalService::Foo inside the service and prevent the service from killing my model?
I know I can just prepend the module but i wanna keep the code readable.
so you are using rails 4
if you want to create a module, first you need to import or autoload your lib folder
for example in application.rb you can add lib folder to autoload:
config.autoload_paths << Rails.root.join('lib')
after that because you are using rails you should create a folder hierarchy with snake cased name of your module hierarchy
for example if you have:
module ExternalService
class Foo
...
end
end
your foo.rb file should be in a folder with name 'external_service'
{{project_root}}/lib/external_service/foo.rb
folder hierarchy is convention of rails.
Ruby behaves just like this and it's totally ok.
In this case the Foo-Model is already loaded, so ruby prefers this instead of the local one. Also alphabetically app/ is before lib/
A not so beautiful but quick fix is just to call it like this:
attribute :foo, ExternalService::Foo

Rails mountable engine with isolate_namespace but without prefixed namespace on tables

Is there a way to configure the isolate_namespace method to not use prefixed table names?
class Engine < ::Rails::Engine
isolate_namespace MyEngine
end
Additionally, an isolated engine will set its name according to namespace, so MyEngine::Engine.engine_name will be “my_engine”. It will also set MyEngine.table_name_prefix to “my_engine_”, changing the MyEngine::Article model to use the my_engine_articles table.Isolated Engine Docs
When designing a prototype I ran into an issue where I need the routes to use the isolated namespace pattern, but the database tables do not. This is because the mountable engine I am writing has it's own self contained database.
Don't want to dig much further if it's not possible.
Rails 3 and 4
Did a little digging into the Rails Engine codebase to find a solution.
If you define a method to specify the table name prefix (in /lib/my_engine.rb), it will just use that instead. So set returning nil works fine.
require "my_engine/engine"
module MyEngine
# Don't have prefix method return anything.
# This will keep Rails Engine from generating all table prefixes with the engines name
def self.table_name_prefix
end
end
For Rails 5, the solution seems to be declaring the following on whatever models you want within your engine:
self.table_name = "name_you_want"
This won't affect generation, but accomplishes the use case that the original poster asks about, I think.

Rails custom generator groups

I've written a custom Rails 3 generator that generates rspec tests for each one of the models in my app. I've also written one for generate rspec tests for routes. When I run
rails generate
I get the following output (this is a segment):
ModelSpec:
model_spec
RouteSpecs:
route_specs
Does anyone know of a way that I could get it to group those like so:
SpecGenerators:
model_spec
route_specs
The directory structure is:
generators/
generators/model_spec
generators/route_specs
Judging from examples of rollbar, kaminari:config and kaminari:views, I assume this is automagically derived from your module structure.
So I guess that if you structure your code like follows, you'll achieve what you want.
#in generators/spec_generators/model_spec_generator.rb
module SpecGenerators
module Generators
class ModelSpecGenerator < Rails::Generators::NamedBase
#in generators/spec_generators/route_specs_generator.rb
module SpecGenerators
module Generators
class RouteSpecsGenerator < Rails::Generators::NamedBase

Resources