Redmine: extend controller action in plugin - ruby-on-rails-3

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.

Related

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

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.

devise after create hook

Is there a hook or callback that I can implement so that right after the user is created, I would like to invoke some custom code ?
I tried after_confirmation hook in the user model but that didn't work.
Use the standard after_create callback provided by Rails.
class User < ActiveRecord::Base
after_create :do_something
def do_something
puts "Doing something"
end
end
Using a callback is perfectly legit if you're dealing with the internal state of the model you created.
After creating a User, I needed to create default a Team. It's preferable to avoid using callbacks to deal with other objects.
“after_*” callbacks are primarily used in relation to saving or persisting the object. Once the object is saved, the purpose (i.e. responsibility) of the object has been fulfilled, and so what we usually see are callbacks reaching outside of its area of responsibility, and that’s when we run into problems.
From this awesome blog post.
In this case it's better to act on the controller, where you can add your functionality directly, or delegate to a service for an even cleaner solution:
# shell
rails g devise:controllers users
# config/routes.rb
devise_for :users, controllers: { registrations: "users/registrations" }
# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
after_action :create_default_team, only: :create
private
def create_default_team
Team.create_default(#user) if #user.persisted?
end
end
I'm using Rails 4 with Devise 3.5 with confirmable and had to do this due to various surprises.
class User < ActiveRecord::Base
# don't use after_create, see https://github.com/plataformatec/devise/issues/2615
after_commit :do_something, on: :create
private
def do_something
# don't do self.save, see http://stackoverflow.com/questions/22567358/
self.update_column(:my_column, "foo")
end
end

Wrong model stub when testing controllers which using inherited_resources

I'm new to RSpec and my controllers're using inherited_resources, I have this mock/stub setup like:
describe MarketsController do
def mock_market(stubs={})
#mock_market ||= mock_model(Market, stubs).as_null_object
end
describe "GET index" do
it "assigns all markets as #markets" do
Market.stub(:all){ [mock_market] }
get :index
assigns(:markets).should eql([mock_market])
end
end
end
And this spec fails because there's nothing in the assigns(:markets). After I added:
class MarketsController
def index
#markets = Market.all
end
end
it'll pass so I guess that's because the inherited_resources doesn't call Market.all to get all of the Market instance and thus bypass the stub for Market.stub(:all). The index method I added above is obviously redundant and shouldn't exist at all, so the question is, without call Market.all explicitly, what should I do in my spec to complete the tests? Thanks in advance!
If I am reading the code correctly, inherited_resources first tries to use Market.scoped if it exists. So do you have a scoped scope?

Rails 3 Engine - Provide Config For Users

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