I have been wrestling with this for the last day and it's driving me NUTS!
As an learning exercise I decided that I would package up some of my code into a Rails Gem. This code has a controller action, a route, a model and a helper so I decided that the most suitable method of creating a Gem would be to create it as a Rails Engine.
Everything seems to be working well, except for one thing. When I try to reference the Model from within a Controller or Views (of an application that uses the engine) e.g.:
@su = Shortener::ShortenedUrl.generate("http://stackoverflow.com")
I get the following error:
uninitialized constant Shortener::ShortenerHelper::ShortenedUrl
It's strange because the error doesn't happen when I execute the code from the projects console. I think that this is caused by the fact I have put all of the code into the "Shortener" namespace/module. I did this so it would help avoid conflicts when used within other applications.
The code file hierachy looks like this:
And here is the class/module declaration code (with the guts removed) of the important files in question
app/controllers/shortener/shortened_urls_controller
module Shortener
class ShortenedUrlsController < ::ApplicationController
# find the real link for the shortened link key and redirect
def translate
# convert the link...
end
end
end
app/models/shortener/shortened_urls
module Shortener
class ShortenedUrl < ActiveRecord::Base
# a number of validations, methods etc
end
end
app/helpers/shortener/shortener_helper
module Shortener::ShortenerHelper
# generate a url from either a url string, or a shortened url object
def shortened_url(url_object, user=nil)
# some code to do generate a shortened url
end
end
lib/shortener/engine.rb
require "rails/engine"
require "shortener"
module Shortener
class ShortenerEngine < Rails::Engine
end
end
lib/shortener.rb
require "active_support/dependencies"
module Shortener
# Our host application root path
# We set this when the engine is initialized
mattr_accessor :app_root
# Yield self on setup for nice config blocks
def self.setup
yield self
end
end
# Require our engine
require "shortener/engine"
shortener.gemspec
require File.expand_path("../lib/shortener/version", __FILE__)
# Provide a simple gemspec so you can easily use your enginex
# project in your rails apps through git.
Gem::Specification.new do |s|
s.name = "shortener"
s.summary = "Shortener makes it easy to create shortened URLs for your rails application."
s.description = "Shortener makes it easy to create shortened URLs for your rails application."
s.files = `git ls-files`.split("\n")
s.version = Shortener::VERSION
s.platform = Gem::Platform::RUBY
s.authors = [ "James P. McGrath" ]
s.email = [ "gems@jamespmcgrath.com" ]
s.homepage = "http://jamespmcgrath.com/projects/shortener"
s.rubyforge_project = "shortener"
s.required_rubygems_version = "> 1.3.6"
s.add_dependency "activesupport" , ">= 3.0.7"
s.add_dependency "rails" , ">= 3.0.7"
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
s.require_path = 'lib'
end
I have published the entire code of the engine on GitHub:
https://github.com/jpmcgrath/shortener
NOTE: this engine has a generator to generate the required migration file. Type:
rails g shortener
I have also created a rails 3.1 app that exhibits the problem (look at line 18 of the projects controller):
https://github.com/jpmcgrath/linky
Any ideas? I have scoured the web, but have not been able to find any really definitive guide to making Engine Gems. Any helpers would be much appreciated.
Thanks!