I'm writing a Rails plugin to extend a Rails engine. Namely MyPlugin has MyEngine as a dependency.
On my Rails engine I have a MyEngine::Foo model.
I'd like to add new methods to this model so I created a file in my plugin app/models/my_engine/foo.rb which has the following code:
module MyEngine
class Foo
def sayhi
puts "hi"
end
end
end
If I enter the Rails console on the plugin dummy application I can find MyEngine::Foo, but runnning MyEngine::Foo.new.sayhi returns
NoMethodError: undefined method `sayhi'
Why MyPlugin cannot see the updates to MyEngine::Foo model? Where am I wrong?
Ok, found out. To make MyPlugin aware and able to modify MyEngine models the engine must be required on the plugin engine.rb like so:
require "MyEngine"
module MyPlugin
class Engine < ::Rails::Engine
isolate_namespace MyPlugin
# You can also inherit the ApplicationController from MyEngine
config.parent_controller = 'MyEngine::ApplicationController'
end
end
In order to extend MyEngine::Foo model I then had to create a file lib/my_engine/foo_extension.rb:
require 'active_support/concern'
module FooExtension
extend ActiveSupport::Concern
def sayhi
puts "Hi!"
end
class_methods do
def sayhello
puts "Hello!"
end
end
end
::MyEngine::Foo(:include, FooExtension)
And require it in config/initializers/my_engine_extensions.rb
require 'my_engine/foo_extension'
Now from MyPlugin I can:
MyEngine::Foo.new.sayhi
=> "Hi!"
MyEngine::Foo.sayhello
=> "Hello!"
See ActiveSupport Concern documentation for more details.
Related
I have an engine that will be installed over an application that uses Active Admin...
After install Active Admin, I need to run my engine installer. This will create a file monkey patching an Active Admin class.
The file looks like this...
module ActiveAdmin
module Devise
# things I need to add...
end
end
So, the question is: where I need to put this file and why?
I used the Railtie's initializer method.
my_engine/lib/admin_invitable/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer "ativeadmin_invitable_patch" do |app|
require_relative "activeadmin_invitable_patch"
end
end
end
my_engine/lib/admin_invitable/activeadmin_invitable_patch.rb
module ActiveAdmin
module Devise
# bla bla
end
end
I am trying to include a module into my resque worker but I keep getting this error -
failed: #<NoMethodError: undefined method `build_page' for RefreshEventCache:Class>
The worker - /app/worker/refresh_event_cache.rb
require File.dirname(__FILE__) + '/../../lib/locomotive/render.rb'
class RefreshEventCache
include Resque::Plugins::UniqueJob
include Locomotive::Render
#queue = :events_queue
def self.perform(url)
build_page(url)
end
end
The Module - /lib/locomotive/render.rb
module Locomotive
module Render
extend ActiveSupport::Concern
module InstanceMethods
def build_page(full_path)
Rails.logger.debug "BUILDING PAGE"
end
end
end
end
Any ideas ?
Have you tried to add the extend ActiveSupport::Concern to the main module Locomotive like this:
module Locomotive
extend ActiveSupport::Concern
module Render
module InstanceMethods
def build_page(full_path)
Rails.logger.debug "BUILDING PAGE"
end
end
end
end
Just guessing,... Ive used the extension with single modules but this seems to be logical for me.
I have a custom plugin (I didn't write it) that is not working on rails 3, however it did work with rails 2. It is for a custom authentication scheme, here is what the main module looks like:
#lib/auth.rb
module ActionController
module Verification
module ClassMethods
def verify_identity(options = {})
class_eval(%(before_filter :validate_identity, :only => options[:only], :except => options[:except]))
end
end
end
class Base
#some configuration variables in here
def validate_identity
#does stuff to validate the identity
end
end
end
#init.rb
require 'auth'
require 'auth_helper'
ActionView::Base.send(:include, AuthHelper)
AuthHelper contains a simple helper method for authenticating, base on a group membership.
When I include 'verify_identity' on an actioncontroller:
class TestController < ApplicationController
verify_identity
....
end
I get a routing error: undefined local variable or method `verify_identity' for TestController:Class. Any ideas how I can fix this? Thanks!
It worked in 2.3 because there was an ActionController::Verification module back there. It's not working in 3.0 because this module doesn't exist. Rather than relying on Rails to have a module that you can hook into, define your own like this:
require 'active_support/concern'
module Your
module Mod
extend ActiveSupport::Concern
module ClassMethods
def verify_identity(options = {})
# code goes here
end
end
end
end
and use:
ActionController::Base.send(:include, Your::Mod)
To make its functions available. ActiveSupport::Concern supports you having a ClassMethods and InstanceMethods module inside your module and it takes care of loading the methods in these modules into the correct areas of whatever the module is included into.
I have found a lot of information about adding form helper methods (see one of my other questions), but I can't find anything about adding helper methods as if they were defined in application_helper.rb.
I've tried copying application_helper.rb from a rails app into the gem but that didn't work.
I've also tried:
class ActionView::Helpers
..but that produces an error.
Create a module somewhere for your helper methods:
module MyHelper
def mymethod
end
end
Mix it into ActionView::Base (such as in init.rb or lib/your_lib_file.rb)
ActionView::Base.send :include, MyHelper
To extends #sdbrown's excellent Answer to Rails 4:
# in in lib/my_rails_engine.rb
require 'my_rails_engine/my_rails_helper.rb'
require 'my_rails_engine/engine.rb'
And
# in lib/my_rails_engine/engine.rb
module MyRailsEngine
class Engine < ::Rails::Engine
initializer "my_rails_engine.engine" do |app|
ActionView::Base.send :include, MyRailsEngine::MyRailsHelpers
end
end
end
and finally
# in lib/my_rails_engine/my_rails_helper.rb
module MyRailsEngine
module MyRailsHelpers
# ...
def your_helper_here
end
end
end
When I add the following block of code in environments.rb, ActiveRecord::Base extends the module in the development environment but not in the test environment.
require "active_record_patch"
ActiveRecord::Base.send(:extend, ModelExtensions)
The library file which contains the module is as follows:
module ModelExtensions
def human_name_for(attr_hash)
# do something
end
end
Loading ./script/server and ./script/console seems fine on the development environment. But on the test environment, the following error occurs:
/home/test/rails_app/vendor/rails/activerecord/lib/active_record/base.rb:1959:in `method_missing':NoMethodError: undefined method `human_name_for' for #<Class:0x4a8d33>
For the solution, I modified the module and included the module to ActiveRecord::Base on the lib file itself:
module HumanAttributes
module ClassMethods
def human_name_for(attr_hash)
unless attr_hash.nil?
##human_names = attr_hash
class << self
def human_attribute_name key
##human_names[key.to_sym] || super unless key.nil?
end
end
end
end
end
end
module ActiveRecord
class Base
extend HumanAttributes::ClassMethods
end
end
This makes human_name_for accessible by any class extending from ActiveRecord::Base on all environments.
Just remember to require the file on the top of model file.
This works for me.
module ModelExtensions
def human_name_for(attr_hash)
# do something
end
end
In environment.rb
include ModelExtensions
ActiveRecord.extend(ModelExtensions)
Then this works ArObject.human_name _for(:asd)