【问题标题】:Rails 5 - generate and run migrations inside a rake taskRails 5 - 在 rake 任务中生成和运行迁移
【发布时间】:2017-07-28 23:43:59
【问题描述】:

所以我有一个应用程序,当我创建一个新用户时,我会在与该特定用户相关的一些其他数据库中设置列。我意识到这不是最佳实践,但对于我的用例来说,它比序列化包含该表的所有用户信息的数组要快得多。

我要做的是设置一个创建User 的 rake 任务,以及对表进行必要的迁移。

这是我目前所拥有的:

  desc "Adds User and creates correct DB entries."
  task add_user: :environment do
    username = ENV['username'].to_s
    email = ENV['email'].to_s
    password = ENV['password'].to_s
    initials = ENV['initials'].to_s
    if username and email and password and initials
      User.create! :username => username, :email => email, :password => password, :password_confirmation => password, :initials => initials
      Rake::Task['generate migration AddPay' + initials + 'ToShoppingLists pay' + initials + ':decimal'].invoke
      Rake::Task['generate migration AddPay' + initials + 'ToPayments pay' + initials + ':decimal'].invoke
      Rake::Task['db:migrate'].invoke
    end
  end

我的问题是在Rails 5 中,我必须运行rails g migration 而不是rake g migration,所以我不确定如何从rake 任务中调用rails 命令。

另外,有没有办法检查是否已经创建了迁移?例如,如果我在开发模式下运行它,我不需要在生产模式下重新创建迁移,只需执行db:migrate

【问题讨论】:

    标签: ruby-on-rails rake ruby-on-rails-5


    【解决方案1】:

    您可以使用Rakesh 方法,只需调用rails shell 命令即可。

    sh "rails g migration AddPay#{initials}ToShoppingLists pay#{initials}:decimal"
    sh "rails g migration AddPay#{initials}ToPayments pay#{initials}:decimal"
    

    当使用 sh 而不是 ruby​​ 内置的 shell 命令的反引号分隔符时,如果命令的退出状态不是 0,它将引发异常并中止任务。

    要查看您的迁移是否已经创建,您只需检查是否存在与命名模式匹配的迁移文件。

    files = Dir.glob Rails.root.join('db/migrate/*')
    
    migration_patterns = { 
      /add_pay_#{initials.downcase}_to_shopping_lists/ => "rails g migration AddPay#{initials}ToShoppingLists pay#{initials}:decimal",
      /add_pay_#{initials.downcase}_to_payments/ => "rails g migration AddPay#{initials}ToPayments pay#{initials}:decimal"
    }
    
    migration_patterns.each do |file_pattern, migration_command|
      if files.none? { |file| file.match? file_pattern }
        sh migration_command
      end
    end
    
    Rake::Task['db:migrate'].invoke
    

    这假设您不会有任何在none? 中引发误报的迁移命名冲突。但是 Rails 不会让你有迁移命名冲突,所以检查可能没有必要。考虑到您命名迁移和列的方式,您似乎最终会遇到这个问题。如果两个用户的姓名首字母相同怎么办?

    是否有一种方法可以通过使用额外的数据库表(可能是多态连接表?)而不是为每个 user 添加列来完成您需要的工作?这些方面的东西可能会起作用:

    class CreateDisbursements < ActiveRecord::Migration[5.1]
      def change
        create_table :disbursements do |t|
          t.decimal :amount
          t.integer :payable_id
          t.string :payable_type
          t.integer :receivable_id
          t.string :receivable_type
    
          t.timestamps
        end
    
        add_index :disbursements, [:payable_type, :payable_id]
        add_index :disbursements, [:receivable_id, :receivable_type]
      end
    end
    
    class Disbursement < ApplicationRecord
      belongs_to :payable, polymorphic: true
      belongs_to :receivable, polymorphic: true
    end
    
    class ShoppingList < ApplicationRecord
      has_many :disbursements, as: :payable
      has_many :users, through: :disbursements, source: :receivable, source_type: 'User'
    end
    
    class Payment < ApplicationRecord
      has_many :disbursements, as: :payable
      has_many :users, through: :disbursements, source: :receivable, source_type: 'User'
    end
    
    class User < ApplicationRecord
      has_many :disbursements, as: :receivable
      has_many :payments, through: :disbursements, source: :payable, source_type: 'Payment'
      has_many :shopping_lists, through: :disbursements, source: :payable, source_type: 'ShoppingList'
    end
    
    user = User.find params[:user_id]
    payment = Payment.find params[:payment_id]
    amount = params[:amount]
    
    payment.disbursements.create(amount: amount, receivable: user)
    user.disbursements.create(amount: amount, payable: payment)
    Disbursement.create(amount: amount, payable: payment, receivable: user)
    user.payments
    payment.users
    

    【讨论】:

    • 谢谢,这是完美的——用户不会有初始冲突,因为它被设置为唯一的。 (它们并不是真正的首字母,更像是 id 键)。我会考虑你的第二个建议,看看是否能保持我需要的速度。
    • 很高兴它有帮助!我在一些 API 的底部添加了一些示例来处理和构建这些关联。根据您需要做什么,此设置可能意味着更多的数据库查询,但我认为它使数据和关系变得灵活且易于使用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 2011-02-07
    • 2011-12-01
    • 1970-01-01
    相关资源
    最近更新 更多