【问题标题】:Rake tasks work on command line, but fail when invoked inside a Rake taskRake 任务在命令行上工作,但在 Rake 任务中调用时失败
【发布时间】:2013-03-19 15:36:13
【问题描述】:

目前,为了为 Rails 项目重建我的数据库,我在命令行中运行以下 Rake 任务:

bundle exec rake db:drop
bundle exec rake db:create
bundle exec rake db:migrate
bundle exec rake db:seed

我想把这些放在一个 Rake 任务中,所以我创建了一个 lib/tasks/db.rake 文件:

namespace :db do
  desc 'Drop and recreate the database(s)'
  task :clean do
    Rake::Task["db:drop"].invoke
    Rake::Task["db:create"].invoke
    Rake::Task["db:migrate"].invoke
    Rake::Task["db:seed"].invoke  # This doesn't work for some reason...
  end
end

前几个任务运行良好,但 db:seed 崩溃并出现一个奇怪的错误:

undefined method `username' for #<User:0xdfaa494>
[...]/gems/activemodel-3.2.12/lib/active_model/attribute_methods.rb:407:in `method_missing'
[...]/gems/activerecord-3.2.12/lib/active_record/attribute_methods.rb:149:in `method_missing'
[...]/lib/acts_as_followable/followable.rb:42:in `method_missing'
[...]/gems/friendly_id-4.0.9/lib/friendly_id/slugged.rb:253:in `should_generate_new_friendly_id?'
[...]/gems/friendly_id-4.0.9/lib/friendly_id/slugged.rb:273:in `set_slug'
[...]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:407:in `_run__819679792__validation__197267883__callbacks'
[...]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:405:in `__run_callback'
[...]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:385:in `_run_validation_callbacks'
[...]/gems/activesupport-3.2.12/lib/active_support/callbacks.rb:81:in `run_callbacks'
[...]/gems/activemodel-3.2.12/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
[...]/gems/activemodel-3.2.12/lib/active_model/validations.rb:195:in `valid?'
[...]/gems/activerecord-3.2.12/lib/active_record/validations.rb:69:in `valid?'
[...]/gems/activerecord-3.2.12/lib/active_record/validations.rb:77:in `perform_validations'
[...]/gems/activerecord-3.2.12/lib/active_record/validations.rb:50:in `save'
[...]/gems/activerecord-3.2.12/lib/active_record/attribute_methods/dirty.rb:22:in `save'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:259:in `block (2 levels) in save'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
[...]/gems/activerecord-3.2.12/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:208:in `transaction'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:259:in `block in save'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:270:in `rollback_active_record_state!'
[...]/gems/activerecord-3.2.12/lib/active_record/transactions.rb:258:in `save'
[...]/gems/activerecord-3.2.12/lib/active_record/relation/finder_methods.rb:294:in `find_or_instantiator_by_attributes'
[...]/gems/activerecord-3.2.12/lib/active_record/dynamic_matchers.rb:52:in `method_missing'
[...]/db/core_data/roles_and_users.rb:7:in `<top (required)>'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `load'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `block in load'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:236:in `load_dependency'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `load'
[...]/db/seeds.rb:20:in `block in <top (required)>'
[...]/db/seeds.rb:19:in `each'
[...]/db/seeds.rb:19:in `<top (required)>'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `load'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `block in load'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:236:in `load_dependency'
[...]/gems/activesupport-3.2.12/lib/active_support/dependencies.rb:245:in `load'
[...]/gems/railties-3.2.12/lib/rails/engine.rb:520:in `load_seed'
[...]/gems/activerecord-3.2.12/lib/active_record/railties/databases.rake:333:in `block (2 levels) in <top (required)>'
[...]/lib/tasks/db.rake:11:in `block (2 levels) in <top (required)>'
[...]/bin/ruby_noexec_wrapper:14:in `eval'
[...]/bin/ruby_noexec_wrapper:14:in `<main>'
Tasks: TOP => db:seed

在命令行或运行应用程序时不会出现此错误。

更新:这里是关于代码库和架构的更多信息。

db/core_data/roles_and_users.rb 的第 7 行:

admin_user = User.find_or_create_by_email('valid@example.com') # not the actual email address used in the file

app/models/user.rb 的部分内容:

class User < ActiveRecord::Base
  include ApplicationHelper, FriendlyId, ActsAsFollowable::Followable, Disableable
  ...
  friendly_id :username, :use => :slugged
  attr_accessible :username
  ...
  username_format = /^[a-z\d]+([-_][a-z\d]+)*$/i
  validates :username, :presence => true, :uniqueness => true, :format => { :with => username_format, :message => "can only contain letters, numbers, underscores (_) or dashes (-). Spaces are not allowed."}, :unreserved_word => true, :length => { :minimum => 3, :maximum => 60 }
  ...
end

username 是数据库中的一个 VARCHAR(255) 字段。

更新 2: 看起来 Rake 环境设置不正确。如果我将db/core_data/roles_and_users.rb 中的第 7 行替换为以下内容:

admin_user = User.create(:email => 'valid@example.com', :username => 'administrator')

那么错误是:

unknown attribute: username

如果我将命令行(有效)手动调用的输出与 Rake 进行比较,我还会输出用户模型:

# Command line invocation -- WORKS
[2013-03-25 09:42:08] INFO  Rails : Connecting to database specified by database.yml
** Invoke db:load_config (first_time)
** Execute db:load_config
** Execute db:abort_if_pending_migrations
Creating badges...
Creating Shipping Options...
  For UPS...
  For USPS...
Creating roles...
Creating users...
User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, last_day_logged_in: datetime, consecutive_days_logged_in: integer, username: string, confirmation_sent_at: datetime, confirmed_at: datetime, confirmation_token: string, failed_attempts: integer, unlock_token: string, locked_at: datetime, super_user: boolean, facebook_id: string, facebook_email: string, fb_auth_token: string, slug: string, forem_admin: boolean, forem_state: string, forem_auto_subscribe: boolean, disabled: boolean, delta: boolean, latitude: float, longitude: float)

# Rake invocation -- DOESN'T WORK
** Invoke db:schema:load (first_time)
** Invoke environment 
** Invoke db:load_config 
** Execute db:schema:load
** Invoke db:seed (first_time)
** Execute db:seed
** Invoke db:abort_if_pending_migrations 
Creating badges...
Creating Shipping Options...
  For UPS...
  For USPS...
Creating roles...
Creating users...
User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime)
rake aborted!
undefined method `username' for #<User:0xdad7fc0>

如您所见,Rake 并没有看到很多模型的字段,即使它们存在于数据库中。

【问题讨论】:

    标签: ruby-on-rails rake


    【解决方案1】:

    我不知道这是否可行,但请尝试:

    namespace :db do
      desc 'Drop and recreate the database(s)'
      task :clean => :environment do
        ...
      end
    end
    

    更新:如果这是您任务的完整代码,您可以定义一个执行其他任务的任务,如下所示:

    namespace :db do
      desc 'Drop and recreate the database(s)'
      task :clean => [:drop, :create, :migrate, :seed]
    end
    

    希望这会有所帮助! :)

    更新 2:我想我没有正确阅读回溯......错误表明您的 User 对象没有定义 username 方法。这可能是由 2 个不同的错误引起的:

    1. 您应该已经手动定义了username 方法。

    2. 您在迁移中添加了一个username 字段,但不知何故它不存在。

    检查迁移的拼写并确认您不需要实施选项 1。然后检查您的 db/core_data/roles_and_users.rb:7 文件(从回溯中提取)。

    如果这不能解决你的问题,我不知道还能做什么:(

    【讨论】:

    • 感谢您的想法,但这并没有解决问题。
    • 我已经用另一个代码更新了答案,希望这会有所帮助:)
    • 编辑(再次)答案!
    • 谢谢mrcasals。我已经用更多信息更新了我的问题。没有明确的username 方法——它是模型中的一个字段。也许验证器在播种时失败了?如果我发现了什么,我会仔细查看并发布更多内容。
    【解决方案2】:

    虽然这是一种迂回的解决方案,但在您的 db:clean 任务中,我会尝试使用 system() 或将 rake 调用包装在反引号中来执行命令,即:

    system("bundle exec rake db:drop")
    system("bundle exec rake db:create")
    system("bundle exec rake db:migrate")
    system("bundle exec rake db:seed")
    

    `bundle exec rake db:drop`
    `bundle exec rake db:create`
    `bundle exec rake db:migrate`
    `bundle exec rake db:seed`
    

    话虽如此,我还没有测试它,但它应该工作。

    【讨论】:

    • 这不是一个完美的解决方案,但它确实有效。请注意,反引号 return 输出,因此如果您想查看它,您必须自己打印它。我还尝试了 exec(),但它取代了 Rake 进程,而不是在子 shell 中运行。
    猜你喜欢
    • 1970-01-01
    • 2016-04-17
    • 2020-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 2013-06-15
    相关资源
    最近更新 更多