【问题标题】:Rails 3, Bundler, LoadErrorRails 3,捆绑器,LoadError
【发布时间】:2010-09-04 02:16:47
【问题描述】:

我正在编写一个应用程序,它将在指定文件夹中运行脚本,然后记录数字并绘制它们。

我的问题是,如果脚本是 ruby​​ 文件,则脚本内部的 require 语句会失败,因为 bundler 似乎对加载路径做了一些奇怪的事情。

运行rails runner Datasource.run_jobs 失败:

class Datasource < ActiveRecord::Base
  def self.run_jobs
    require 'aws_sdb'
    access_key_id = "REDACTED"
    secret_key = "REDACTED" # In all actuality these woudln't be here.
    @sdb = AwsSdb::Service.new(:access_key_id => access_key_id, :secret_access_key => secret_key)

    Datasource.all.each do |ds|
      puts "Updating #{ds.name}..."
      unless @sdb.list_domains.include? ds.name
        puts "#{ds.name} doesn't exist in SDB, creating a domain for it..."
        @sdb.create_domain ds.name
      end

      #data = "TEST"
      data = `#{RAILS_ROOT}/lib/plugins/#{ds.name}`

      @sdb.put_attributes(ds.name, Time.now.to_i, data)
      puts "Data Collected: #{data.inspect}"
    end
  end

  has_many :graphs

end

【问题讨论】:

  • 失败并显示什么错误信息?
  • @Ryan Bigg,我不想在我的 Gemfile 中要求每个 gem。我想要一个充满脚本的文件夹(Ruby 和非 ruby​​ 之类的),ruby 将使用反引号迭代并在系统上执行。然后,我的 rails 应用程序会将每个文件的输出记录到数据库中。不应该要求那些依赖于 Rails 应用程序中的 gem。我应该能够在系统原生上下文中执行它。
  • @webdestroya,我面前没有确切的错误消息,但它是 LoadError -- hpricot 错误。这是因为 data = #{RAILS_ROOT}/lib/plugins/#{ds.name} 行尝试执行包含 require hpricot 的 ruby​​ 脚本。
  • (后者)只是为了检查这里 - 带有require hpricot 的ruby 脚本是否有require 'rubygems' 前面?我想确保您正确地认为问题在于捆绑程序实际上破坏了系统调用的加载路径,而不是脚本具有未声明的依赖项。我会假设反引号转义的命令不会知道捆绑程序。

标签: ruby-on-rails ruby-on-rails-3 bundler


【解决方案1】:

(根据您的问题,根据您的 cmets)

您需要将 hpricot(以及任何其他需要的 gem)添加到您的 Gemfile,以便 Bundler 可以使用它们。 Bundler 是到目前为止避免 gem 冲突和愚蠢行为的最简单方法。

想象一下这种情况:你不知何故失去了你目前拥有的宝石。这是通过格式或系统更改或任何其他原因发生的。不管是什么,你已经失去了你的宝石。你将如何重新安装所有的 gem?您可以自己在其他地方保存一份清单,但这真的有可能吗?

Bundler 通过让您说明应用程序需要哪些 gem 并仅将这些 gem 添加到加载路径来解决此问题,这就是您找不到 hpricot 的原因。当你第一次运行bundle install 时,这会创建一个Gemfile.lock,其中包含如下内容:

GEM
  remote: http://rubygems.org/
  specs:
    abstract (1.0.0)
    actionmailer (3.0.0)
    ...

因为您将此文件提交到您选择的源代码控制“解决方案”(无论是 Git、SVN、FTP 等等,这并不重要),因此您有一种可靠的方式来指定您所需要的精确 gem 和这些 gem 的精确版本应用程序使用。

当/如果您的 gem 被擦除,您可以简单地再次克隆您的项目并运行 bundle install。因为存在 Gemfile.lock 文件,所以即使有更新,您也会拥有与原来完全相同的 gem。

如果您不想要 完全相同 相同的 gem,只需运行 bundle update,这将忽略 Gemfile.lock 中的规范,而是恢复为依赖 Gemfile 来定义它们。这将检查新版本的 gems 并安装它们,完成后更新 Gemfile.lock

老实说,我不明白 Bundler 的仇恨。如果你能用比“天哪,耶胡达是撒旦”更广泛的术语来解释,我将非常感激。

编辑:WedTM 要求提供示例 Gemfile 和相关代码:

在 Gemfile 中你会有这个:

group(:scripts) do
  gem 'gem1'
end

要为您的脚本要求这些 gem:

require 'bundler'
Bundler.require(:scripts)

您可能还希望需要默认 gem,只需在 require 的参数的任何位置添加默认值即可:

Bundler.require(:default, :scripts)

如果由于某种原因这不起作用,我想那是因为它无法找到Gemfile。这可以通过将ENV['BUNDLE_GEMFILE'] 设置为Gemfile 的路径来解决。

【讨论】:

  • Ryan,我真的很喜欢 bundler 的那个部分,它确实让它变得更容易了!但是,我认为您在我的问题中没有看到的部分是正在运行的文件不是我的 rails 应用程序的一部分。它只是系统上驻留在文件夹中的脚本。我碰巧让我的 Rails 应用程序循环遍历该文件夹中的每个文件,并记录它的输出。如果我在我的 rails 应用程序的外部运行文件,它会按预期工作,但在应用程序的上下文中运行它(rails runner 'Method. contains_a_call_to_said_script' 它会失败。
  • @WedTM:然后需要 Bundler,将其指向您的 Gemfile,然后将脚本 gem 放入一个名为“script”的组中,并使用 Bundler.require(:script) 包含它们?
  • 瑞恩,如果你能给我一个例子,这个问题和非常感谢你。
  • @WedTM:已更新。试一试。
  • Ryan,我仍然错过了我不想使用 Gemfile 的观点。我希望人们在我的应用程序中上传/编辑脚本。这些脚本是使用 Ruby 编写的。在 cron 期间,我想在该目录中运行这些脚本。
【解决方案2】:

我想知道您是否可以在运行脚本之前使用 RVM 设置 ruby​​ 环境。也许像这样的宝石:

data = `rvm gemset use scripts; #{RAILS_ROOT}/lib/plugins/#{ds.name}`

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2020-10-27
    • 1970-01-01
    • 2019-03-08
    相关资源
    最近更新 更多