簡體   English   中英

Rails 5-在rake任務中生成並運行遷移

[英]Rails 5 - generate and run migrations inside a rake task

所以我有一個應用程序,當我創建一個新用戶時,我在與該特定用戶相關的其他一些數據庫中設置了列。 我意識到這不是最佳做法,但就我的用例而言,它比序列化一個包含該表所有用戶信息的數組要快得多。

我想要做的是設置一個rake任務,該任務創建User ,並進行必要的表遷移。

這是我到目前為止的內容:

  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

您可以使用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的內置backtick分隔符來執行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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM