从Rails 3.1引擎中访问模型

5
我已经花了一整天的时间在这个问题上苦苦挣扎,但它却让我感到很疯狂!
作为一个学习练习,我决定将我的代码打包成Rails Gem。这个代码包括一个控制器动作、一个路由、一个模型和一个辅助函数,因此我认为创建一个Rails Engine是最合适的方法。
除了一个问题外,似乎一切都工作得很好。当我尝试从控制器或视图(使用引擎的应用程序)中引用模型时,例如:
@su = Shortener::ShortenedUrl.generate("http://stackoverflow.com")

I get the following error:

uninitialized constant Shortener::ShortenerHelper::ShortenedUrl

很奇怪,因为当我从项目控制台执行代码时,错误不会发生。我认为这是由于我将所有代码放入“Shortener”命名空间/模块中造成的。我这样做是为了在其他应用程序中使用时避免冲突。

代码文件层次结构如下所示:

An image of the project directory/file listing

以下是相关重要文件的类/模块声明代码(已删除实质内容)

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

应用程序/模型/缩短器/缩短的URL

module Shortener
  class ShortenedUrl < ActiveRecord::Base

    # a number of validations, methods etc  

  end 
end

应用程序/助手/缩短器/缩短器助手

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

我已经将整个引擎的代码发布在GitHub上: https://github.com/jpmcgrath/shortener 注意: 此引擎有一个生成器,可以生成所需的迁移文件。输入:
rails g shortener

我还创建了一个 Rails 3.1 应用程序来展示这个问题(请查看项目控制器的第18行): https://github.com/jpmcgrath/linky 有什么想法吗?我已经搜索了整个网络,但没有找到关于如何制作引擎宝石的真正权威指南。任何帮助都将不胜感激。
谢谢!

这里应该有一些迁移,如果没有它们,我无法测试您的引擎。 - Benoit Garret
我已经从Github测试了你的代码,看起来运行良好(我只添加了一个迁移)。你的Rails应用程序使用哪个版本?我使用了最终版3.1,也许这就是区别所在。 - Benoit Garret
谢谢Benoit。Github的代码有一个生成器可以创建迁移。只需输入"rails g shortener"。我会修改我的问题,包括这个。 - James P McGrath
关于Rails版本,我认为可能是问题所在,但是我的gem文件中有“gem'rails','3.1.0'”。我将创建另一个GitHub项目,将我的测试应用程序推送到其中。 - James P McGrath
1个回答

3
在您的引擎助手 (app/helpers/shortener/shortener_helper.rb) 中,将两个 ShortenedUrl 的出现替换为 Shortener::ShortenedUrl
一开始我觉得这个错误很奇怪,因为 Ruby 应该在封装模块中查找常量。但帮助程序包含在另一个类中,这可能意味着常量名称解析环境与文件中看到的不同。
如果您想了解有关命名空间引擎及其行为的更多信息,可以查看这个优秀的答案

Benoit,你真是个传奇,让我受益匪浅!很奇怪的是,当从应用程序中调用助手的代码时,它是正常工作的。我猜在某个地方出现了混淆。我应该去学习一下Ruby名称解析 :-) - James P McGrath
如果你能找出这里到底发生了什么,那将是答案的绝佳补充;-) - Benoit Garret
1
好的,希望一些了解命名空间/名称解析/引擎方面的专家能够路过并提供启示,不是说我在寻找捷径什么的 :-) - James P McGrath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接