11

I've been working on my first Rails 3 plugin, to package up a simple helper function that I like having in the ApplicationHelper of all my apps. You can see the whole code on Github.

Here's my first attempt:

## lib/semantic_id.rb ##

require 'semantic_id/version'

module ::ActionView::Helpers::TextHelper

  def semantic_id
    string = String.new

    case
    when controller.action_name =~ /new|edit/
      string += controller.action_name + "_"
    when controller.action_name =~ /index|create/
      string += controller.controller_name
    else
      string += controller.controller_name.singularize
    end

    string += "_view"
  end

end

Now, this works, but as I understand it this is not the 'Rails 3 Way' of extending ActiveSupport or any other Rails module. I haven't been able to find much documentation on how you're "supposed" to build a Rails 3 gem. I tried following the Rails Guide, but the method given there for adding helpers didn't work, or else I was missing something.

My question is: given the code above as an example of the functionality I'm looking for, how would you turn this into a Rails 3 plugin Gem?

Thanks!

Andrew
  • 42,517
  • 51
  • 181
  • 281
  • you should try using the jeweler gem in creating your gem :) – corroded Jul 13 '11 at 20:05
  • 1
    Regarding the answers given, I'm torn because I relied on both to solve this problem. Alex's code got me close, but I was still having a hard time figuring out how to make it load in the app until Noli posted his links to better examples of how to put a railtie together. So in the end, Alex's answer got me started while Noli's helped me finish. I have to go with Noli in this case, as his links made the difference in the end. Thank you both for your considerate answers! – Andrew Jul 14 '11 at 03:08

1 Answers1

17

The problem with what you've done is that you've bound your gem's functionality to ActionView. It would be better to make it more generic.

To fix this you should package your code in its own module and then inject that module into your view environment. For example, put your helper into its own module (and file):

# lib/semantic_id/helper.rb

module SemanticId
  module Helper
    def semantic_id
      ...
    end
  end
end

Then add it to ActionView using a Railtie:

# lib/semantic_id.rb

require 'semantic_id/helper'

ActiveSupport.on_load(:action_view) do
  include SemanticId::Helper
end

You want to separate the functional part of the helper from the part that inserts it into the framework. Your method contains some Rails-specific code, but if it didn't this technique would allow you to use it with Sinatra and other frameworks as well.

In general, the guts of your project should be in lib/<project_name>/*.rb, and lib/<project_name>.rb should just make the functionality accessible.

Alex Reisner
  • 29,124
  • 6
  • 56
  • 53