Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling methods everywhere in a Ruby on Rails application

I am using Ruby on Rails 3.0.9 and I am trying to make it possible to call some methods from all inside helper, controller, models and view files. What I would like to make is to create a library to build\standardize naming conventions internally to my application so that I can use\run something like the following:

standardized_name = standardize_name(Article)

What do you advice about?

P.S.: I have heard of mixin, but how should I use those in my case? Furthermore I would like not to state inclusion of that mixin in each class that need to use that (that is, I would like to have a "unique" statement that includes the mixin in all my application classes).

like image 307
Backo Avatar asked Dec 28 '22 16:12

Backo


2 Answers

A similar library that's accessible in all layers of the Rails MVC is I18n. You can call the translate method with I18n.t while there's a helper t method in the view and controller layer so you don't need to type the entire "I18n.t" every time.

We can follow how I18n did it. You can create a module in the lib directory of your application. Make sure to update application.rb so that your module is loaded. Look for this comment in application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

Obviously, if you uncomment the autoload_paths line, change "extras" to "lib".

Here's an example module lib/Karate.rb:

module Karate
  class << self
    def punch(grunt)
      puts "#{grunt}! *punch*"
    end
  end
end

Now you can call this anywhere in your application:

Karate.punch("boom")
# => boom! *punch*

If you want a helper method in your View and Controller layers, just add a method in application_controller.rb:

def punch(grunt)
  Karate.punch(grunt)
end

And declare this method as a helper method (also in application_controller.rb), like so:

helper_method :punch

BUT, please make sure you really need this library. I didn't question your reason because it will not answer your main question. I think you should just practice your naming convention in your code, add it in README if you have to or send an email to your team. Also, Rails and Ruby has naming conventions already, so be sure to learn about it as well.

like image 91
mikong Avatar answered Jan 30 '23 13:01

mikong


Depending on your use case, you can take one of these approaches to rather attach the method to the objects it acts on. Then you don't need to include the standardize_name method everywhere you want to use it; you just centralized it on the objects to which it applies:

To use as Article.standardized_name (class method):

If your standardize_name method only takes ActiveRecord models as arguments, consider putting it in a module (in lib/standardizable.rb for example) and extending it onto ActiveRecord::Base (or some other class that is a parent to all your domain classes):

module Standardizable
  def standardized_name
    # in here, self will be the model *class*,
    # so the following will return "Article" if you
    # extended the module into the Article class:
    self.name
  end
end

# include the mixin in all ActiveRecord models:
ActiveRecord::Base.extend Standardizable

Alternatively, if you don't want to include it in all models, just include the module into the individual classes where you want standardized_name to be available:

class Article < ActiveRecord::Base
  extend Standardizable
end

With both of the following approaches, you will be able to use the method like so:

standardized_name = Article.standardized_name

To use as Article.new.standardized_name (instance method):

If you'd rather use the method on instances of your model classes, just change extend in the above example to include:

module Standardizable
  def standardized_name
    # in here, self will be the model object *instance*,
    # so the following will return "Article" if you
    # included the module into the Article class:
    self.class.name
  end
end

# include the mixin in all ActiveRecord models:
ActiveRecord::Base.send(:include, Standardizable)

The usage then looks like this:

article = Article.new

standardized_name = article.standardized_name

Wrapping up with ActiveSupport::Concern:

A nice way to wrap up both these approaches in Rails 3 is with ActiveSupport::Concern:

module Standardizable
  extend ActiveSupport::Concern

  module ClassMethods
    def standardized_name
      self.name
    end
  end

  module InstanceMethods
    def standardized_name
      self.class.standardized_name
    end
  end
end

ActiveRecord::Base.extend Standardizable

Then you can use both the class and instance method to get the standardized name:

standardized_name_from_class = Article.standardized_name
article = Article.new
standardized_name_from_instance = article.standardized_name
like image 29
Jacob Avatar answered Jan 30 '23 11:01

Jacob