rails consoleに簡単にオプションを足せるようになるgemを作った
作ったgemはこれです
使い方
config/application.rb
に下のようにオプションをセットします。Rails::Application
の上に書くようにしてください。
Bundler.require(*Rails.groups) D4C::Console.add_option 'hello' do puts "hello" end module YourRailsApplication class Application < Rails::Application
これでrails console
に渡せるオプションを追加できました。実際にオプションが呼ばれると渡したブロックがcall
されます。
rails c --hello Running via Spring preloader in process 7922 hoge Loading development environment (Rails 5.2.3) irb(main):001:0>
なんで作ったか
rails console
を叩くときに、「デフォルトで実行されたくないけど実行したいときはさっと実行したい」処理があったからです。
職場でact_as_tenant
というgemを使っています。dbのレコードに制限をかけるgemです。act_as_tenant
の都合上、rails consoleからdbのレコードを叩くには
ActsAsTenant.without_tenant do end
として作業しなくてはなりませんでした。
とはいえRailtie
のconsole
メソッドでせっかくかけたセキュリティをデフォルトで外してしまうことはしたくありません。--sandbox
みたいにオプションで選択できると良いと考え、このgemを作りました。 1
実装の話
そもそもrails console --sandboxをした時の流れ
bin/rails console
自体の具体的な流れはRailsガイドにとっても詳しく書いてあるので読みましょう。
では--sandbox
はどうやって処理されているのでしょうか。
(注 Railsのコードを載せていますが色々省いています。)
Rails::Command::ConsoleCommand
クラスは下のようになっています。
class_option :sandbox, aliases: "-s", type: :boolean, default: false, desc: "Rollback database modifications on exit." def perform Rails::Console.start(Rails.application, options) end
受け取れるコマンドラインのオプションをclass_option
で追加しています。Rails::Command::ConsoleCommand
はThorというコマンドラインツールの作成を助けるgemを継承しています。class_option
はそのgemのメソッドです。
Rails::Application
クラス内では--sandbox
が入力されたかを保存できるようにしてあります。
attr_accessor :assets, :sandbox
Rails::Console
クラスでは、コマンドラインから渡されたオプションの有無をアプリケーションのインスタンスに渡しています。
def initialize(app, options = {}) @app = app @options = options app.sandbox = sandbox? end def sandbox? options[:sandbox] end
これによりif app.sandbox
で条件分岐できるようになります。
実際にD4Cで行った拡張
module Rails Application.prepend D4C::PrependOptionAccessor Console.prepend D4C::PrependOptionSetter Command::ConsoleCommand.prepend D4C::PrependClassOption end
D4CのmoduleはD4C::Console.add_option
に渡されたオプションをRailsのクラスが扱えるようにするものです。 それぞれprepend
してmoduleの中でsuper
することで処理を足しています。D4C::Console
の中身はオプションを構造体にして保存するクラスのインスタンスです。
Gemの名前
ジョジョの奇妙な冒険のスタンド名です。
最初はbaby_faceって名前でした、コンソールなので。
ディ・モールトベネなgemの名前だと思いながら作成して、いざ公開しようと思ったら同じ名前のgemが既にあって泣きました。皆さんはこうならないようにちゃんとrubygemsで名前を検索してから作りましょう。
最終的にたやすくオプションを足せるってところからD4Cにしました。
最後にこれが一番書きたかったんですけど、D4Cってまさに「Ruby」だと思うんですよね。