Rails 3 Engine - Provide Config For Users - ruby-on-rails-3

I can't seem to find any documentation on how to do the following: I need to provide a config variable for any applications using my engine so that they can easily pass settings to my engine.
Does anyone have any links to a proper or accepted way to do this?
EDIT: As an update, I figured out a decent way to do this. Code is below.
# file: lib/my_engine.rb
module MyEngine
class Engine < Rails::Engine
initializer "my_engine.configure_rails_initialization" do |app|
# Engine configures Rails app here, this is not what my question was about
end
end
# This is what I was trying to figure out
def self.config(&block)
##config ||= MyEngine::Configuration.new
yield ##config if block
return ##config
end
end
This allows any application using my engine to configure it like below in any of their initializers or their environment.rb file, calling any methods defined in the MyEngine::Configuration class:
MyEngine.config do |config|
config.some_configuration_option = "Whatever"
end

Short answer:
Create a file called your_engine_class.rb and put in config/initializers of your hosting app. Here is an example of this file.
module YourEngineClass
class Engine < Rails::Engine
config.param_name = 'value'
end
end
Then inside your main engine.rb you can access:
config.param_name
Longer answer: I created a stub engine that includes this and lots of other standard configuration you'll need, you can use it as a starting point:
http://keithschacht.com/creating-a-rails-3-engine-plugin-gem/

I personally like the pattern Devise uses, which defines a class method in your engine's module and then an initializer in the parent application.
Create a class method to call from the parent application
module YourEngine
class << self
attr_accessor :your_config_var
end
def self.setup(&block)
# You can yield your own object encapsulating your configuration logic/state
yield self
end
end
Call the class method in an initializer in the parent application
YourEngine.setup do |config|
config.your_config_var = "nyan cat"
end
Now you are free to access your_config_var in your engine's initialization process. You can create a file in your engine's config/initializers directory or use the Rails Initializer hooks.
I like this approach since you have more control on what configuration object you expose to clients and aren't overriding the engine's config method.

Seems better to me as follow :
#lib/my_engine.rb
require 'rails'
module MyEngine
class Engine < Rails::Engine
end
def self.config(&block)
yield Engine.config if block
Engine.config
end
end

Related

Create module that throws exception in rails if conditions not met on load

I have a module in a rails 3 app that's included in multiple models. I want to force the app to fail to load if any of the models do not have an appropriate attr_accessor defined. Due to the architecture of the app it's not feasible to include the attr_accessors as a part of the module to be added to the class during the self.included function.
Here's what I've tried at present:
module MyModule
def included(base)
raise "Accessor 'enabled' is not defined in #{base.name}" unless base.method_defined? :enabled
end
end
class MyModel < ActiveModel::Base
# attr_accessor :enabled
attr_accessor :attr_1, :attr_2
include MyModule
end
In this instance, I'd want the app to fail to load because MyModel does not have an enabled method.
Your code should work - on production. In development the classes in app/models are only loaded if used unless you set
config.cache_classes = true
in config/environments/development.rb. But that makes developing really no fun, since you have to restart your webserver every change to test your changes. On rails 4 you have another configuration option
config.eager_load = true
So you do not need to cache classes to get the behaviour to have loaded every class on starting your server / console.
If it's really only attribute accessor you check, it's better just to set it on including the module. And if you work with modules in rails: have a look into http://www.rubydoc.info/docs/rails/3.2.8/ActiveSupport/Concern
There you can just call attr_accessor :enabled in the included block.

Redmine: extend controller action in plugin

Need some help in plugin development.
I've created hook in user/edit form view, added ballance_amount to form and have "ballance_amount"=>"1".
How can I extend default update action in user controller?
In base.class_eval do I've added alias_method_chain :update, :ballance
In InstanceMethods:
def update_with_ballance
ballance.amount = params[:user][:ballance_amount].to_f #I have ballance association
end
And get this:
NameError (undefined local variable or method `params' for #<User:0x007f972e9379d0>):
app/controllers/users_controller.rb:144:in `update'
How can I fetch params?
You should be able to make use of the mass-assignment code in the Redmine itself. Line 135 in the UsersController should handle provide you with a simple entry point for your extension, if balance_amount is considered a safe_attribute. To achieve that, add a patch like the following to the User model:
module RedmineBalancePlugin::UserPatch
def self.included(base)
base.class_eval do
safe_attributes 'balance_amount'
include InstanceMethods
end
end
module InstanceMethods
# This method is indirectly called when creating or updating a User
def balance_amount=(amount)
balance.amount = amount
end
# This could be useful in your view patch, but maybe not
def balance_amount
balance.amount
end
end
end
User.send(:include, RedmineBalancePlugin::UserPatch)
If this example does not help, it would be helpful, if you could provide more code fragments - e.g. the complete patch to the UsersController, to make it easier to reproduce and analyse the issue.

Rails - include module into controller, to be used in the view

I'm really new to Rails and I try to setup a module file to be used in the view. So I believe the correct behavior is to define the module as a helper within a controller and voila, it should be working. However, that's not the case for me. Here is the structure.
lib
functions
-- form_manager.rb
form_manager.rb:
Module Functions
Module FormManager
def error_message() ...
end
end
end
users_controller.rb
class UsersController < ApplicationController
helper FormManager
def new ...
Well, the structure is like the above and when I call the error_message from new.html.erb it gives me the error: uninitialized constant UsersController::FormManager.
So, first of all, I know that in rails 3 lib is not automatically loaded. Assuming that it is not mandatory to autoload the lib folder, how can I make this work and what am I missing?
BTW, please don't say that this question is duplicate. I'm telling you I've been searching for this crap for almost 2 days.
Your module is not autoloaded (at least not in 3.2.6). You have to load it explicitly. You can achieve this with the following line of code
# in application.rb
config.autoload_paths += %W(#{config.root}/lib)
You can check your autoload paths with Rails.application.config.autoload_paths. Maybe it's indeed defined for you?
Now you're sure your module gets loaded, you can check it in rails console by calling
> Functions::FormHelper
Now you can't use that module as a view helper by default. Use #included to define the helper when your module gets included. You achieve "lazy evaluation" this way. I think the problem with your code is that the helper method gets called before the module gets included. (somebody should correct me if I'm wrong)
Here's the code:
Module Functions
Module FormManager
def error_message() ...
end
def self.included m
return unless m < ActionController::Base
m.helper_method :error_message
end
end
end
You should also remove the helper line from your controller.
EDIT:
You can achieve this without autoloading. Just use require "functions/form_manager". You define a helper_method for every method. If you wish use all the module methods as helpers use
def self.included m
return unless m < ActionController::Base
m.helper_method self.instance_methods
end
EDIT2:
It appears that you don't need to use self.included. This achieves the same functionality:
class ApplicationController < ActionController::Base
include Functions::FormManager
helper_method Functions::FormManager.instance_methods
end
It appears you are namespacing FormManager inside of Functions which means you would call it by helper Functions::FormManager
Try that

How do I test a helper method in my application_helper file in Rails 3?

My application_helper.rb file:
module ApplicationHelper
def option_text(option_id)
Option.find(option_id).title
end
end
Where do I test this method at? Rails generates helper test files when I create a scaffold, but where do I put a test for this method, since it's in the Application Helper? I have tried placing the test in one of the view helper test files generated with the scaffold, but it can't find the method above.
Add a folder under test/unit called 'helpers', then create your helper test files like this:
# application_helper_test.rb
require File.dirname(__FILE__) + '/../../test_helper'
require 'action_view/test_case'
class ApplicationHelperTest < ActionView::TestCase
test 'option_text' do
assert true
end
end
There are some other helpful tips on testing helpers here:
http://technicalpickles.com/posts/helper-testing-using-actionview-testcase/

Writing a custom attr_special function in Rails 3

Apologies in advance - I'm very much a learner, and writing projects as a means to learn. In this one, I'm trying to extend ActiveRecord so that I can do the following...
In my model definition, call ...
attr_special :field, :field
Then, elsewhere, be able to access this list through something like
Model.special_attributes
Probably something really obvious. I'm fine extending ActiveRecord, but I'm not even sure what I'm searching for for guidance beyond this (constructor?)...
You can define something like the code below to create custom DSL in your models:
module SpecialAttributes
module ClassMethods
def attr_special(*attrs)
class_attribute :special_attributes
self.special_attributes = attrs
end
def special_attributes
self.special_attributes
end
end
module InstanceMethods
# some code here
end
def self.included(base)
base.extend ClassMethods
base.send :include, InstanceMethods
end
end
class ActiveRecord::Base
include SpecialAttributes
end
I reopen ActiveRecord::Base class instead of use inheritance because it's more common in Ruby that inheritance.
I like to use submodules called ClassMethods and InstanceMethods in my module and use self.included method to add them in the base class. So you can use 'include MyModule' without have to know if you add instance or class methods.
I hope I can help you.