I'm studying some Rails 3 code from Spree:
module Spree
module Generators
class SiteGenerator < Rails::Generators::Base
source_root File.expand_path("../../templates", __FILE__)
desc "Configures an existing Rails application to use Spree."
def create_lib_files
template 'spree_site.rb', "lib/spree_site.rb"
end
def additional_tweaks
remove_file "public/index.html"
append_file "public/robots.txt", <<-ROBOTS
.... continues ....
This works with Rails 3, but I've looked up Rails::Generators::Base, following the inherited modules to Rails::Generators::Actions and the Thor classes, but still can't seem to find api documentation on the #template method. I can figure out what it does, but I'm troubled that I can't find the docs on it. It's got me feeling like a real newbie (though, since I haven't worked with Rails in quite awhile, I guess in some ways I am).
Any help would be appreciated. Please tell me why I'm not able to find this (and other) methods in the Rails api docs. What am I missing???
The template method is an instance method included with Thor::Actions and can be found at http://rubydoc.info/gems/thor/0.14.6/Thor/Actions:template
Related
Running rails zeitwerk:check returns expected file app/api/mariana_tek_client.rb to define constant MarianaTekClient
The odd thing is that I have the following class defined in this file, which seems to follow the convention that I've seen documented: project/app/api/mariana_tek_client.rb
module Api
class MarianaTekClient
include HTTParty
end
end
If I remove the module from the file and leave the class definition only, Zeitwerk stops failing, but this is contrary to what I've seen in all its docs. Plus, I want my namespace!
This works:
class MarianaTekClient
include HTTParty
end
Would love if someone can clue me into why its failing with the namespace.
I'm guessing you've added app/api as an extra autoload path. If so, Zeitwerk will look in that folder for classes in the root namespace, and subfolders for classes in modules - so it expects app/api/mariana_tek_client.rb to contain MarianaTekClient; if you want Api::MarianaTekClient then that would need to go in app/api/api/mariana_tek_client.rb.
You could point Zeitwerk at app, and it would then look for Api::MarianaTekClient in app/api/mariana_tek_client.rb; but that is discouraged and would probably cause you more problems in the long term.
I'd recommend using the default Zeitwerk configuration, and putting your model classes under app/models; so it would then look for Api::MarianaTekClient in app/models/api/mariana_tek_client.rb - as would anyone else working on your code.
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
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.
I'm quite a beginner with Ruby On Rails and I need to implement client part of JSON API in order to use some external service.
I found a gem called jsonrpc and it looks perfect for me.
I've added it to my Gemfile as:
gem 'jsonrpc'
gem 'json'
and ran bundle
My code looks like this:
class SearchController < ApplicationController
def index
d = JsonRpcClient.new 'http://remote.bronni.ru/Dictionaries.ashx'
#countries = d.getCountries
end
But when I try to access it as http://localhost:3000/search, Rails says:
NameError in SearchesController#index
uninitialized constant SearchController::JsonRpcClient
I only have little experience with Rails so I'm asking you guys to help me out.
I really need to get this to work ASAP.
Thank you all in advance! I really appreciate your help!
UPDATE
I've tryed to get ActiveResource to work but I can't get how it build URL's. The remote service is not a Ruby XML app. (http://remote.bronni.ru/Dictionaries.ashx) And I need to use getCountries method so the URL should be http://remote.bronni.ru/Dictionaries.ashx/getCountries
Within my Rails application I have a module defined this way:
module WhateverModule
class WhateverClass
...
end
end
This file (whatever_class.rb) is located under /app/models/whatever_module
const_missing is being overriden by Rails and despite I did some workarounds, involving initializers, I wish I could make it in a better way.
My aim is to get a WhateverModule::Foo (Foo being undefined) to be resolved by a custom const_missing method.
Any help will be greatly appreciated. Thanks in advance!!
The following seems to work fine for me in Rails 2.2.2
module WhateverModule
def self.const_missing(c)
# handle missing constant
end
end