Monkey Patching Devise (Or Any Rails Gem)

Monkey patching Devise (or any Rails gem)

If you try to reopen a class, it's the same syntax as declaring a new class:

class DeviseController
end

If this code is executed before the real class declaration, it inherits from Object instead of extending the class declared by Devise. Instead I try to use the following

DeviseController.class_eval do
# Your new methods here
end

This way, you'll get an error if DeviseController has not been declared. As a result, you'll probably end up with

require 'devise/app/controllers/devise_controller'

DeviseController.class_eval do
# Your new methods here
end

Where to put code when monkey patching

There is no set rule on this. Technically you can open it (the class; and add your method) anywhere. I usually make a special file called monkey_patches.rb and put it in config/initializers or in a misc folder in my Rails app so if theres ever a conflict I know where to look.

Also I'd advise to use a Module to wrap the monkey patch. Check out 3 ways to monkey patch without making a mess for more info.

His example:

module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end

DateTime.include CoreExtensions::DateTime::BusinessDays

how to use monkey patching helper in devise in password controller to change after_sending_reset_password_instructions_path_for

There are several how-to articles on the Devise Wiki that may provide straightforward solutions to the problem you're trying to solve. One might be here: https://github.com/plataformatec/devise/wiki/How-To:-Change-the-default-sign_in-and-sign_out-routes, and another here: https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in-out

Note that Devise has gone through a lot of changes recently (new version 2.0 is out) that addresses many of the challenges earlier adopters had through better documentation and by exposing hooks that weren't readily available before. I urge you to consider using the new version. My team dealt with many frustrations and difficulties with the earlier version, and we quickly learned that messing with the internals of Devise frequently had unintended consequences. It's a really great gem, especially its OAuth integration, but it does a lot, and has very clear opinions on how to do things.

When monkey-patching a single method in a gem can I make it aware of an active record in my app?

I'd store it in a plain class

class StoreRecord
def self.activeRecord
@active_record
end
def self.activeRecord=(record)
@active_record = record
end
end

so your code becomes

StoreRecord.activeRecord = ... # gets an ActiveRecord object that I want to update 
options = {..}
@gem_object = SomeLibrary::Class.new(options)

@gem_object.someMethod()

and you can access StoreRecord.activeRecord in your patched method.

Rails bootstrap gem monkeypatching method not working

The problem is that you patch the method on this module but the module already got included at this point. Try to define this in your application_helper.rb

def name_and_caret(name)
super("blub #{name}")
end

Monkey Patching Mongoid models contained in a Ruby gem

I think I've nailed this now. Rather than putting the monkey patch inside lib/models, I moved them to lib/sorting_office/models and required them like so:

require 'sorting_office/models/street'
require 'sorting_office/models/locality'
require 'sorting_office/models/town'
require 'sorting_office/models/postcode'

I'd still be interested to know WHY this worked though

Ruby on Rails Monkey Patching a Gem's Model

First of all instead of reopening the class I would create a Module and include it into the Person. So it would look like that

  module CustomString
def to_custom_string
address.street.to_s
end
end

Person.send(:include, CustomString)

Also it seems like the Person model is not yet available at the point of running the initializer. You may want to put this in your application.rb if still doesn't work.

  config.railties_order = [ModelEngine::Engine, :main_app, :all]

I guess the reason why it works in irb and not in rake is because they look up classes differently. Irb (which I believe you run by running rails console) loads all the classes at once therefore it loads the classes from engine, then it runs the initializer where you have the classes from engine already defined. I guess (though I'm not sure) Rake in development mode uses lazy loading of constants. So it doesn't load all the classes at the very beginning and only when it finds a constants that is undefined. Then it starts looking for a file that may define that constant. Since you put some Person in initializer it doesn't look up the engine's model at all cause at the point it sees Person it has the Person definition already. That's why the inclusion of module instead of reopening the class may help -> it enforces that it will lookup the Person constant from engine.

Monkey Patching in Rails 3

The initializer directory is a good place to collect all those little scraps. Since I tend to go a bit overboard with core extensions, I like to make a folder there called "extensions" and toss them all in there.

So, try /config/initializers/string_extension.rb, or /config/initializers/extensions/string.rb, or something similar. Either way, you can just forget about them afterward - Rails will require them for you, so you don't need to do it yourself.

Monkey patching a core class with business logic with Rails

Where should finder.rb be?

Ultimately, it doesn't matter. It only matters that this code gets loaded. This mix of patching base libraries and adding business logic there looks like something that MUST be documented thoroughly (in the project's wiki or something like that). And if it is documented, then it doesn't matter. The code is where the documentation says it is.

That being out of the way, here's a design suggestion:

when user seeks a Family Family.find(params[family_id],session[:company_id]), this find will compare the company of the family result family.company witht the parameter

Why not do something like this:

family = current_company.families.find(params[:family_id])

where current_company can be defined as @current_company ||= Company.find(session[:company_id])

Here, if this company doesn't have this family, you'll get an exception.

Same effect*, only without any patching. Much more futureproof. You can even add a couple of rubocop rules to ensure that you never write a naked Family.find.


* it's not like you add that patch and rest of your code magically acquires super-powers. No. You still have to change all the finders, to pass that company id.



Related Topics



Leave a reply



Submit