1

I'm debugging rails app (Redmine) and each time I change something in plugin's routes or library that patches base class I have to restart rails sever even while its in development mode with caching turned off etc..

This is how my server looks like:

rails s
=> Booting WEBrick
=> Rails 3.2.16 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2017-02-02 17:06:18] INFO  WEBrick 1.3.1
[2017-02-02 17:06:18] INFO  ruby 2.1.8 (2015-12-16) [x86_64-darwin15.0]
[2017-02-02 17:06:18] INFO  WEBrick::HTTPServer#start: pid=12042 port=3000

Does anyone know of a way to force the app to partially reload classes that were affected or with such change or?

Aleksandar Pavić
  • 3,143
  • 1
  • 34
  • 36
  • Some aspects of a Rails app are only executed/interpreted when the server starts, like initializers and stuff. – MurifoX Feb 02 '17 at 16:09

3 Answers3

2

the startup process takes quite some time in rails. most of that time is due to loading the gem dependencies. if you want to do that on every request never the less, there are some ways to do it like described here:

as initializers are run only during initialization, it makes sense that rails does not re-run them. if you rely on monkey-patching, there are ways around that described in here

Community
  • 1
  • 1
phoet
  • 18,688
  • 4
  • 46
  • 74
2

You probably load patches from the init.rb file of your Redmine plugin. It's a good practice to surround them with:

ActionDispatch::Reloader.to_prepare

Using this callback, patches will be re-applied before each request in development mode.

Here is an example:

require 'redmine'
ActionDispatch::Reloader.to_prepare do
  require_dependency 'redmine_multiprojects_issue/issue_patch'
  require_dependency 'redmine_multiprojects_issue/issues_helper_patch'
  require_dependency 'redmine_multiprojects_issue/issues_controller_patch'
end
Redmine::Plugin.register :redmine_multiprojects_issue do
  ...
end

Note that you still have to restart the server if you change the routes.

Nanego
  • 1,890
  • 16
  • 30
  • ah yeah! i was looking for this callback, but could not remember what it was called! – phoet Feb 03 '17 at 09:45
  • But would this way cause slowdowns, and unnecessary reloads in production? Should I only use it during development? – Aleksandar Pavić Feb 03 '17 at 20:21
  • 2
    This is the beauty of using this callback - the block will only be called once in production mode since Rails' code reloading is disabled then, but it will be called everytime code is reloaded in development mode. There's a couple variations of this, I've been using `Rails.configuration.to_prepare do` recently, works the same. – jkraemer Feb 04 '17 at 01:49
0

Redmine plugins are usually not Ruby gems but live in a folder inside the main Rails app.

As long as the plugin author follows a few Rails best practices, Rails' autoloading should (and will) also work with Redmine plugins. The basic things to pay attention to are:

  • proper naming and namespacing - have subdirectories corresponding to modules and file names corresponding to the class / module they declare, i.e. Foo::Bar::Baz lives in lib/foo/bar/baz.rb
  • never require stuff manually, but let Rails autoload everything
  • be careful when and where you patch things to have patches re-applied during automatic reloading

If a plugin author follows these rules, the plugin's code will most probably autoload and reload just fine. One exception is the plugin's init.rb, but this usually doesn't change very often during plugin development.

In practice, a lot of Redmine plugins break auto loading due to violation of these rules. Symptoms can be no automatic reloading, or even an application error when reloading is attempted, resulting in an application that works fine in production mode, but fail after the first successful request in development mode.

Often simply re-organizing the plugin code to match Rails' expectations and removing require statements is all it takes to fix this kind of problem.

Changing the routes declared by a plugin will require a restart of the server nevertheless, I do not know of a way to have these reloaded automatically with Redmine.

jkraemer
  • 357
  • 1
  • 6
  • Hi, Thanks for the headstart... Can you give some examples here. The reason being, I have always required in init.rb and also the patch applied when rails *to_prepare events are done. – rupeshj Feb 03 '17 at 06:49
  • Applying patches in `to_prepare` blocks is the way to go. The thing is, you should not `require` anything manually. With proper naming and namespacing, even using `require_dependency` is not necessary. Though if you have to, the latter is always better as it will not break Rails' code reloading. – jkraemer Feb 04 '17 at 01:51