2017-07-28 6 views
0

新しいユーザーを作成するときに、その特定のユーザーに関連する他のデータベースに列を設定するというアプリがあります。これはベストプラクティスではありませんが、私のユースケースでは、そのテーブルのすべてのユーザー情報を保持する配列をシリアライズするよりもはるかに高速です。Rails 5 - 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を実行してください。

答えて

1

Rakeshメソッドを使用して、railsシェルコマンドを呼び出すことができます。

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

とは対照的に、shを使ってRubyの組み込みのシェルコマンドのバッククォートの区切り文字、コマンドは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はネーミングの衝突を起こさせないので、チェックは必要ないかもしれません。最終的には、移行と列の名前付けの方法を考えれば、この問題に直面するように思えます。 2人のユーザーのイニシャルが同じ場合はどうなりますか?

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 
+0

ありがとう、これは完璧です - ユーザは初期の衝突が発生しません。 (これらはidキーのようなイニシャルではありません)。私はあなたの第2の提案で亀裂があり、あなたが必要とするスピードを保つかどうかを確認します。 – Darkstarone

+1

助けてくれてうれしい!これらの関連付けを行い、作成するためのAPIの一番下にいくつかの例を追加しました。あなたが何をする必要があるかによって、この設定はより多くのdbクエリを意味するかもしれませんが、データとリレーションシップを柔軟にし、使いやすくすると思います –

関連する問題