Rails: class methods helpers from Lib - ruby

Sorry the title may not be very clear. Basically I have a wrapper for the Split gem called ABFeature in lib/ab_feature/ab_feature.rb
In my view I want to be able to call my helpers like this:
ABFeature.current_settings
But this is not working, here is the error I have:
undefined local variable or method `session' for ABFeature:Module
session is a method from ActionController and is seems I can't access it...
Here is my code:
require 'split'
module ABFeature
class << self
include Split::Helper
def current_settings
...
end
end
end
class ActionController::Base
ActionController::Base.send :extend, ABFeature
end
Any idea?,
Greg

I'm not sure what the result should be but if you want the current_settings method available in the controller I think you can do
module ABFeature
include Split::Helper
def current_settings
end
end
and then
class ApplicationController < ActionController::Base
include ABFeature
end
I think you usually call helpers as instance methods. Then they should share the context with the controller.

Related

Inheriting module/class methods

I have this module with a method:
module MySqlConnection
def database_connect(application)
# Code in here
end
end
I have a second module with a class that uses database_connect:
module ResetPopups
class PopupsOff
include MySqlConnection
def self.reset_popup
database_connect("#{APP}")
end
end
end
When I call:
ResetPopups::PopupsOff.reset_popup
I get an undefined method database_connect. Why does this happen?
include adds module methods as instance methods, while extend adds them as singleton methods. Since you want to use this in the context of class (singleton context), you need to use extend:
extend MySqlConnection
module ResetPopups
class PopupsOff
extend MySqlConnection
def self.reset_popup
database_connect("#{APP}")
end
end
end
would work
What is hapening here, is that you include MySqlConnection, which makes method defined in it (database_connect) instance methods. But you use this module in the class scope, calling the database_connect on the class.

Have superclass methods call class in correct namespace

I have some namespaces that contain duck-type classes, and they all inherit from Base namespace, like below:
module Base
class Client
def self.greet
puts Wrapper
end
def do_stuff
puts Wrapper
end
end
class Wrapper
end
end
module Website
class Client < Base::Client
end
class Wrapper < Base::Wrapper
end
end
Website::Client.greet
Website::Client.new.do_stuff
---output---
Base::Wrapper
Base::Wrapper
I would like the above code to print (and reference) Website::Wrapper instead, is there a way to accomplish this by changing my inheritance structure?
If a constant named Wrapper is in the top-level namespace you can write ::Wrapper to refer to it, but usually just writing Wrapper is sufficient.
In Website::Client, if I attempt to call another class such as
Wrapper, it will call Base::Wrapper...
I'm not seeing that:
module Base
class Client
end
class Wrapper
end
end
module Website
class Wrapper < Base::Wrapper
end
class Client < Base::Client
p Wrapper #=>Website::Wrapper
def self.greet #Create class method
p Wrapper #=>Website::Wrapper
end
def do_stuff
p Wrapper #=>Website::Wrapper
end
end
end
Website::Client.greet
Website::Client.new.do_stuff
--output:--
Website::Wrapper
Website::Wrapper
Website::Wrapper
Can you modify that example to show the problem you are having?
Response to modified question:
Is this just bad practice?
Wouldn't it be surprising to call Base::Client.greet and get Website::Wrapper?
Is there an easy way to have methods called in the subclass default to
that class' namespace?
What do you mean by that? There is no class method named greet defined in Website::Client's singleton class. If you want to override Base::Client.greet you can do that.
Also, you are writing Website::Client when you call Website::Client.greet, so you already know from which class the method call originates...but inside Base::Client.greet, you can add the line puts self, and that will identify the object that called the method, which is the class Website::Client.

Define instance method of a class after class already defined in ruby

I have some problem with extending class with instance method after separate module is included into separate class
module ActsAsCommentable
def self.included(commentable)
Thread.class_eval do
def commentable
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
class Thread
#some code...
end
class Asset
include ActsAsCommentable
end
And now I want to call this method somelike this:
thread = Thread.new
thread.commentable
The problem is, of course is that there is no binding with include method for class eval, and I could save variables that I want to pass into class eval in ActsAsCommentable module, but I dont want to. Is there a better way?
I tried to do instead
module ActsAsCommentable
def self.included(commentable)
class << Thread
define_method :commentable do
p "disqusable is #{commentable}"
p "disqusable class is #{commentable}"
end
end
end
end
But As I guessed this creates instance method for singletone object of class and therefore I can call it only through
Thread.commentable
And again, no binding...
If I understand you correctly, you need to be able to access the commentable variable inside your Thread extension, right?
If so, just change this:
Thread.class_eval do
To this:
Thread.class_exec(commentable) do |commentable|
And it should work.

Use an object from outside your modules scope

I have code like this.
class User < ActiveRecord::Base
end
module Foo
class User
end
end
module Foo
class DoesSomethingWithActiveRecordUser
def initialize user_id
User.find(user_id)
end
end
end
If I call Foo::DoesSomethingWithActiveRecordUser.new(1) I get an error message that says something like undefined method 'find' for Foo::User.
How do I call the ActiveRecord User from within Foo?
Thanks.
Like this:
::User.find(user_id)

Create property as method on class in Ruby

Rails has these cool properties that seem to be actually methods. For example:
class SomeController < ApplicationController
before_filter :authenticate!
end
What are these actually called and how would you create your own? For example, in one of my models I want to be able to have a dynamic property that selects an internal method for processing some results:
class MyModel < ActiveRecord::Base
active_method :some_class_method
end
How would I set this up so I can set active_method like that and be able to access the active_method symbol as an instance var?
Edit for elaboration:
So give this starter below, I need to figure out how to define "selected_method" so that it defines a accessor or instance variable so "called_selected_method" calls "method_b".
class MyClass
selected_method :method_b
def call_selected_method
end
private
def method_a
puts 'method_a'
end
def method_b
puts 'method_b'
end
end
c = MyClass.new
c.call_selected_method # should put 'method_b'
It's actually just a method call to a method defined on the class. before_filter is provided by a ruby Module, which is mixed in to ActionController.
Creating your own methods similar to before_filter is as easy as:
Define a class method on your Class
Call that method in any concrete implementations of your class.
Some example code:
class MyClass
class << self
def some_function(*args)
# your code here
end
end
some_function "foo"
end
If you wanted to abstract it further, you can put the class method in to a Module, and then include that module in to your class(es).
UPDATE:
In relation to your asking of how to get a call of some_function to set an instance variable on your class, you can't, as class methods cannot affect specific instances of that class.
I have to wonder, though... you're writing a method that will just act as a proxy to your other method, and would be hard-coded in to the class definition. That offers no benefit to you, and would just make your code redundantly complicated.

Resources