I want to override a method from Redmine Core using a Patch in a plugin but I'm not able to make it working :-(.
I want to change the behavior of the method try_to_login from the Redmine core.
Here is my Init.rb:
require 'redmine'
require 'user_patch'
ActionDispatch::Callbacks.to_prepare do
require_dependency 'project'
require_dependency 'principal'
require_dependency 'user'
unless User.included_modules.include? UserPatch
User.send :include, UserPatch
end
end
Redmine::Plugin.register :security do
name 'Security plugin'
author 'Author name'
description 'This is a plugin for Redmine'
version '0.0.1'
url 'http://example.com/path/to/plugin'
author_url 'http://example.com/about'
end
and my patch file:
module UserPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method :try_to_login, :try_to_login_with_patch
end
end
module InstanceMethods
# Returns the user that matches provided login and password, or nil
def try_to_login_with_patch(login, password, active_only=true)
<do somthing ...>
end
end
end
Any idea what is wrong in this ?
Thanks you in avance.
Regards,
Aniss
i've done this already in my plugin:
https://github.com/berti92/mega_calendar
init.rb - within Redmin::Plugin.register...
Rails.configuration.to_prepare do
UsersController.send(:include, UsersControllerPatch)
end
in the lib folder create a file "issues_controller_patch.rb"
module IssuesControllerPatch
def self.included(base)
base.class_eval do
# Insert overrides here, for example:
def create_with_plugin
create_without_plugin
## your code ##
end
def update_with_plugin
update_without_plugin
## your code ##
end
alias_method_chain :update, :plugin
alias_method_chain :create, :plugin
end
end
end
create_without_plugin means the original code will be executed. If you dont want it, then delete the create_without_plugin and update_without_plugin
Related
New to Ruby\Rails, shame on me :(
I'm developing an engine for personal use (simple admin panel). What I want, is to be able to config my main app's models, like this:
class User < ActiveRecord::Base
include Entropy::Configurable
entropy_config do
form_caption 'Editing user'
end
end
And then in engine's templates do this:
<h1><%= #object.entropy_config :form_caption %></h1>
Engine's module:
module Entropy
module Configurable
def self.included(base)
## to call entropy_config in model class
base.send :extend, ClassMethods
end
def entropy_config(arg)
## ... I'm missing this part
end
module ClassMethods
##config = { ... }
def entropy_config (&block)
class_eval &block
end
def form_caption(arg)
// skipping class identification
##config[:user][:form_caption] = arg
end
end
end
end
The problem is that I can not get access to ##config from Configurable module, actually when I call entropy_config on #object. What I'm doing wrong?
First of all you've doing it wrong. Rails is on of the frameworks that pushed a lot on the MVC architecture. Having your model know about form captions is wrong. For that I would use the rails i18n gem. For the sake of the argument here's some untested code that will probably answer your question:
module Entropy
module Configurable
def self.included(base)
## to call entropy_config in model class
base.send :extend, ClassMethods
end
def entropy_config(key)
self.class.config[:user][key]
end
module ClassMethods
cattr_accessor :config
def entropy_config (&block)
self.config ||= {}
class_eval &block
end
def form_caption(arg)
// skipping class identification
self.config[:user][:form_caption] = arg
end
end
end
end
see http://apidock.com/rails/Class/cattr_accessor for more info
I am trying to create a gem to extend Rails ActionView Renderer to print an HTML comment with the partial view name bring rendered.
I tried the normal way:
module MyGem
class Engine < ::Rails::Engine
initializer 'mygem.initialize' do
::ActiveSupport.on_load(:action_view) do
::ActionView::Renderer.send :include, MyGem::ViewRenderer
end
end
end
end
And then in mygem/lib/view_renderer.rb:
module MyGem
module ViewRenderer
module InstanceMethods
def render(context, options)
puts "here" # Just to test it was included and it doesn't print
if options.key?(:partial)
render_partial(context, options)
else
render_template(context, options)
end
end
end
def self.included(base)
base.send :include, InstanceMethods
end
end
end
However, when I use render from my views, the test line added doesn't work.
Any idea what am I doing wrong?
This is how I have done it in the past, maybe it will help.
module MyModule
def self.included(base)
def render
#do stuff
end
end
end
ActionController::Base.send :include, MyModule
Then just require the file
I have developed two plugins and they both modify the same method of the same class via alias_method_chain that result into stack level too deep error.
first plugin:
Rails.configuration.to_prepare do
require 'issue_patch'
Issue.send :include, IssuePatch
end
module IssuePatch
module InstanceMethods
def editable_custom_field_values_with_sort(user=nil)
editable_custom_field_values_without_sort(user).sort
end
end
def self.included(receiver)
receiver.send :include, InstanceMethods
receiver.class_eval do
alias_method_chain :editable_custom_field_values, :sort
end
end
end
Second plugin modify the class same way but with different feature:
Rails.configuration.to_prepare do
require 'issue_patch'
Issue.send :include, IssuePatch
end
module IssuePatch
module InstanceMethods
def editable_custom_field_values_with_some_stuff(user=nil)
editable_custom_field_values_without_some_stuff(user).select { |c| c.have_stuff? }
end
end
def self.included(receiver)
receiver.send :include, InstanceMethods
receiver.class_eval do
alias_method_chain :editable_custom_field_values, :some_stuff
end
end
end
When I trying to call this method I got:
ActionView::Template::Error (stack level too deep):
plugins/my_plugin/lib/issue_patch.rb:8
One possible but hack solution is simple monkey patch the redmine code with first plugin feature so the second plugin can alias it without any error.
So how I can fix this error?
The problem was:
I define two modules with the same name IssuePatch so the first module overwrites the second but
Issue.send :include, IssuePatch
still exists in 2 places (for each plugin) and the same module (doesn't matter which one overwrites the other) so the same module were included 2 times and the same alias_method_chain were called 2 times.
The solution: I just add separate module for each plugin and included them like this:
Issue.send :include, FirstPlugin::IssuePatch
Issue.send :include, SecondPlugin::IssuePatch
I have done a module in lib directory in ruby on rails application
its like
module Select
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def select_for(object_name, options={})
#does some operation
self.send(:include, Selector::InstanceMethods)
end
end
I called this in a controller like
include Selector
select_for :organization, :submenu => :general
but I want to call this in a function
i.e
def select
#Call the module here
end
Let's clarify: You have a method defined in a module, and you want that method to be used in an instance method.
class MyController < ApplicationController
include Select
# You used to call this in the class scope, we're going to move it to
# An instance scope.
#
# select_for :organization, :submenu => :general
def show # Or any action
# Now we're using this inside an instance method.
#
select_for :organization, :submenu => :general
end
end
I'm going to change your module slightly. This uses include instead of extend. extend is for adding class methods, and include it for adding instance methods:
module Select
def self.included(base)
base.class_eval do
include InstanceMethods
end
end
module InstanceMethods
def select_for(object_name, options={})
# Does some operation
self.send(:include, Selector::InstanceMethods)
end
end
end
That will give you an instance method. If you want both instance and class methods, you just add the ClassMethods module, and use extend instead of include:
module Select
def self.included(base)
base.class_eval do
include InstanceMethods
extend ClassMethods
end
end
module InstanceMethods
def select_for(object_name, options={})
# Does some operation
self.send(:include, Selector::InstanceMethods)
end
end
module ClassMethods
def a_class_method
end
end
end
Does that clear things up? In your example you defined a module as Select but included Selector in your controller...I just used Select in my code.
I'd like to 'add on' some code on a model's method via a module, when it is included. I think I should use alias_method_chain, but I don't know how to use it, since my 'aliased method' is one of those methods ending on the '=' sign:
class MyModel < ActiveRecord::Base
def foo=(value)
... do stuff with value
end
end
So this is what my module looks right now:
module MyModule
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
alias_method_chain 'foo=', :bar
end
end
module InstanceMethods
def foo=_with_bar(value) # ERROR HERE
... do more stuff with value
end
end
end
I get an error on the function definition. How do get around this?
alias_method_chain is a simple, two-line method:
def alias_method_chain( target, feature )
alias_method "#{target}_without_#{feature}", target
alias_method target, "#{target}_with_#{feature}"
end
I think the answer you want is to simply make the two alias_method calls yourself in this case:
alias_method :foo_without_bar=, :foo=
alias_method :foo=, :foo_with_bar=
And you would define your method like so:
def foo_with_bar=(value)
...
end
Ruby symbols process the trailing = and ? of method names without a problem.