How to extend a class from an initializer and have it reload in development environment?
environment.rb
config.to_prepare do
User.send :include, Qwerty::Core::Extensions::User
end
The code is the block is run before every request in development mode and once in production mode.
How to properly extend ApplicationRecord in Rails 6 with Zeitwerk
Figured it out! The issue was there was an explicit require in an initializer that loaded ApplicationRecord.
# config/initializers/setup_other_fancy_thing.rb
require 'application_record'
module OtherFancyThing
def also_fancy
puts 'also fancy'
end
end
ApplicationRecord.send(:include, OtherFancyThing)
The way I debugged this was that I:
- Created a new Rails app of the same version and could not reproduce the error
- I copied the default application.rb and development.rb and still got the error
- Moved the entire
config/initializers
directory to a temp directory and it made the warning go away! So, I knew it had to be one of the initializers. From there it was just a matter of dividing and conquering until I found the offending initializer.
Reload rails initializers
Initializers are only loaded when starting rails (and never reloaded). When tinkering in config/initializers
you will have to restart rails every time.
Of course, you could make sure your code is defined in /lib
so you can still make sure it works, by using your test-suite.
E.g. in lib/speaker.rb
write
module Speaker
def speak
puts "Ahum, listen: #{self.to_s}"
end
end
and in your initializer you could then do something like
class String
include Speaker
end
While this will still only get loaded when starting rails, you can develop and test your module more easily.
Hope this helps.
Ruby on Rails: Configure API in initializer in development
Well, until someone comes up with a better solution, I've come up with two workarounds. I went with 2.
- Don't autoload the
lib
directory (meaning don't autoload the API). That means having to restart the server when the API code changes, but solves the problem. That's why configuring gems like this works -- because they aren't autoloaded. Manually reload the initializer in development at the end of
lib/my_api.rb
:load Rails.root.join('config/initializers/smart_meter.rb') if Rails.env.development?
The MyApi
constant will be replaced by a new one when Rails autoloads classes. The configuration is still available on the old object:
Loading development environment (Rails 4.2.0)
irb: warn: can't alias context from irb_context.
irb(main):001:0> MyApi.my_setting
=> "foo"
irb(main):002:0> OldMyApi = MyApi
=> MyApi
irb(main):003:0> reload!
Reloading...
=> true
irb(main):004:0> MyApi.my_setting
=> nil
irb(main):005:0> OldMyApi.my_setting
=> "foo"
irb(main):006:0> load Rails.root.join('config/initializers/smart_meter.rb')
=> true
irb(main):007:0> MyApi.my_setting
=> "foo"
Extend model in plugin with has_many using a module
I think this should work
module Qwerty
module Core
module Extensions
module User
# Instance Methods Go Here
# Class Methods
module ClassMethods
def relate
has_many :hits, :uniq => true # no method found
before_validation_on_create :generate_code # no method found
end
def something # works!
"something"
end
end
def self.included(base)
base.extend(ClassMethods).relate
end
end
end
end
end
The old code is wrong cause the validation and the association are called upon module loading, and this module knows nothing about ActiveRecord. That's a general aspect of Ruby, code inside class or module bodies is called directly when loaded. You don't want that. To get around that you can use the above solution.
Why do includes in Rails Engine initializers malfunction when cache_classes = false?
I managed to solve this problem using a to_prepare
block instead of the initializer. The to_prepare
block executes once in production and before each request in development, so seems to meet our needs.
It wasn't obvious when I was researching Rails::Engine
since it is inherited from Rails::Railtie::Configuration
.
So instead of the code in the question, I would have:
module MyApp
class Engine < ::Rails::Engine
config.to_prepare do
AnotherApp::Product.send :include, MyApp::ProductExtender
end
end
end
How to configure DCEVM just to reload only modified class?
HotswapAgent is free alternative to JRebel. It is extension to DCEVM that supports many Java frameworks and servlet containers. There is also documentation howto setup IDE to use DCEVM + HotswapAgent correctly.
Related Topics
Is There a Definitive Reference Document for Ruby Syntax
Ruby/Rails - How to Create a Class and Access It from the Controller
Download File from S3 to Rails 4 App
Gemfile.Lock Always Has Changes Not Staged for Commit
Update Rails to a Specific Version
How to Associate a CSS/Sass Stylesheet to a View in Rails
Sass: Dealing with The Ie 4095 Selectors Per Stylesheet Restriction
Os X Mavericks Install Rvm Warning
Initialize Two Variables on Same Line
Add External Style Sheet in Rails Project
Sorting an Array of Arrays in Ruby
How to Get Ruby-Debug-Ide to Work
How to Profile Rspec with Perftools and Bundler
Application.CSS Not Being Served as an Asset
Undefined Method 'Reset' for Rdoc::Toplevel:Class When Installing a New Ruby Gem
Carrierwave: Create 1 Uploader for Multiple Types of Files
Using Ruby 2.0 on Amazon Opsworks
Why Does Using '-Webkit-Appearance: None' on a Select Option in Osx Make The Text Disappear