パパエンジニアのアウトプット帳

30歳に突入した1児のパパエンジニアのブログ

herokuのDBをローカルのDB(Docker)にリストアする

1. herokuのDBのバックアップを取得する

下記のコマンドを実行。

heroku pg:backups capture --app アプリ名

2. herokuのDBのコンソール画面でバックアップしたファイルをダウンロード

コマンドからでもできるみたいだけど、今回は画面から。

herokuのダッシュボードから行くか、https://data.heroku.com/へアクセスした対象のDBへ行ってダウンロードボタンを押す。

3. Dockerのpostgresqlへインポート

下記のコマンドを実行。

cat ダウンロードしたバックアップファイル | docker exec -i [container_id or name] pg_restore --verbose --clean --no-acl --no-owner -U ユーザ名 -d DB名


以上。

administrateでacts-as-taggable-onと連携できるようにする

最近、管理画面をadministrateで作ってみたが、 acts-as-taggable-onが設定されたモデルをうまく表示する方法が分からなかった。。


試行錯誤の結果、一応できるようになったのでメモとして残す。

やったこと

  • app/dashboards/xxx_dashboard.rbにtagsをField::HasManyで定義
  • acts_as_taggable_onのtagとtaggingdashboardを生成
  • 生成したdashboard/controllerを移動・修正
  • config/routes.rbの設定

app/dashboards/xxx_dashboard.rbにtagsをField::HasManyで定義

acts_as_taggableを定義しているモデルのxxx_dashboard.rbにtagsを定義する。

(例えば、bookモデルにacts_as_taggableを定義している場合はbook_dashboard.rb)

  ATTRIBUTE_TYPES = {
    # ...
    tags: Field::HasMany.with_options(class_name: "::ActsAsTaggableOn::Tag"),
  }

  COLLECTION_ATTRIBUTES = {
    # ...
    :tags,
  }

  SHOW_PAGE_ATTRIBUTES = {
    # ...
    :tags,
  }

  FORM_ATTRIBUTES = {
    # ...
    :tags,
  }

administrateのField::HasManyができると編集画面などで便利なので、Field::HasManyでできるようにするのが目標だった。

acts_as_taggable_onのtagとtaggingdashboardを生成

administrateのgenarateコマンドを実行する。

$ bundle exec rails generate administrate:dashboard ActsAsTaggableOn::Tag
$ bundle exec rails generate administrate:dashboard ActsAsTaggableOn::Tagging

生成したdashboardを移動・修正

$ mkdir app/dashboards/acts_as_taggable_on
$ mkdir app/controllers/admin/acts_as_taggable_on
$ mv app/dashboards/tag_dashboard.rb app/dashboards/acts_as_taggable_on/
$ mv app/controllers/admin/tags_controller.rb app/controllers/admin/acts_as_taggable_on/
$ mv app/dashboards/tagging_dashboard.rb app/dashboards/acts_as_taggable_on/
$ mv app/controllers/admin/taggings_controller.rb app/controllers/admin/acts_as_taggable_on/

生成したままのclass ActsAsTaggableOn::TagDashboardなどのままでもいいが、私は下記のようにmoduleでネームスペースを切るようにした。

module ActsAsTaggableOn
  class TagDashboard < Administrate::BaseDashboard
    #...

    # Overwrite this method to customize how tags are displayed
    # across all pages of the admin dashboard.
    #
    def display_resource(tag) ←コメントアウトされているのを解除。ここが新規/編集時のtagsに表示される項目名になる
      tag.name
    end
  end
end
module ActsAsTaggableOn
  class TaggingDashboard < Administrate::BaseDashboard
    #...
  end
end
module Admin
  module ActsAsTaggableOn
    class TagsController < Admin::ApplicationController
      # ...
    end
  end
end
module Admin
  module ActsAsTaggableOn
    class TaggingsController < Admin::ApplicationController
      # ...
    end
  end
end

config/routes.rbの設定

各画面でacts-as-taggable-on関連のパスも生成しようとするのでroutes.rbの設定をしておく。

  namespace :admin do
    #...

    namespace :acts_as_taggable_on do
      resources :tags
      resources :taggings
    end
  end

これで、acts-as-taggable-onを利用しているモデルのdashboardでもCRUDがhas_manyと同様でできるようになる。

ただ、tagやtaggingは表示のみで新規/編集/削除が画面からできないのでできるようにしたいところ(まだ、直近で必要無いので今は保留)

ネームスペースで区切られたモデルはまだサポートされてなさそう。 下記のpull requestが取り込まれると解決するか?

Add support for namespaced models by shvetsovdm · Pull Request #871 · thoughtbot/administrate · GitHub

2017/06/27 追記

最新のmasterブランチだと上記のpull requestも取り込まれていて、HasOneもサポートされています!



一応、Qiitaの方にも投稿しておいた。 qiita.com

HerokuのDBにimportする

下記のコマンドを実行。

heroku pg:psql --app アプリ名 DATABASE_URL < sqlファイル


※dockerでpostgresqlをインストールして利用している場合は、ローカルにpostgresqlをインストールしていないと怒られる

herokuでridgepole用のDB設定をする

まあ、下記にある通りなんだけど。

www.wantedly.com

herokuのpostgresqlのDATABASE_URLは下記のような形式になっているので、config/database.ymlをそれように変更する。

postgres://username:password@hostname:5432/db_name

activeadminでログインにDeviseではなくSorceryを利用する

管理画面をサクッと作成できるactiveadminで、ユーザ認証にDeviseではなくSorceryを利用したのでその手順を紹介。

※前提としてactiveadminは導入済みとします

1. sorceryをインストール

Gemfileにsorceryを記述して、bundle install

[Gemfile]
・・・
gem 'sorcery'
・・・

2. sorceryの設定ファイルなどを生成

rails generate sorcery:installを実行


※remember_meなどのsubmodulesも設定したい場合はドキュメントを参照。

※初回のbundle installでpathオプションを指定した人はbundle exec rails generate sorcery:installですよ。念のため初心者の為に補足。

3. db:migrateを実行

手順2. でmigrationファイルが生成されているのでrails db:migrateを実行。

4. 認証関連のController/Viewの作成

DeviseのようにビルドインでControllerやViewはないので、ログインに必要なものを自分で作ります。

※すごく簡易なログイン画面とログイン/ログアウト処理を実装します


  • app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def new
    @user = User.new
  end

  def create
    login(params[:user][:email], params[:user][:password])

    # redirect_toの代わりにsorceryのredirect_back_or_toでもOK
    redirect_to admin_dashboard_path ← admin_dashboard_pathはactiveadminが定義したdashboardへのパス
  end

  def destroy
    logout

    redirect_to new_session_path
  end
end
  • app/views/sessions/new.html.erb
<h2>Log in</h2>

<%= form_for @user, url: sessions_path do |f| %>
  <div>
    <%= f.text_field :email %>
    <%= f.password_field :password %>
  </div>

  <div>
    <%= f.submit "Log in" %>
  </div>
<% end %>


コントローラー作成したのでconfig/routes.rbも設定します。

  • config/routes.rb
Rails.application.routes.draw do
  ActiveAdmin.routes(self)

  resources :sessions, only: %i(new create)
  delete 'sign_out', to: 'sessions#destroy'

  ・・・
end

5. activeadminの設定の変更

sorceryの準備がやっと完了したので、やっとactiveadminとsoceryの連携部分です。

やることはドキュメントにあるとおり、config/initializers/active_admin.rbの設定を行います。


下記のコメントアウトを外してsorcery用の設定をしますです。

  • config.authentication_method
  • config.current_user_method
  • config.logout_link_path
  • config.logout_link_method
   #
   # This setting changes the method which Active Admin calls
   # within the application controller.
-  # config.authentication_method = :authenticate_admin_user!
+  config.authentication_method = :require_login

   # == User Authorization
   #
@@ -86,7 +86,7 @@ ActiveAdmin.setup do |config|
   #
   # This setting changes the method which Active Admin calls
   # (within the application controller) to return the currently logged in user.
-  # config.current_user_method = :current_admin_user
+  config.current_user_method = :current_user

   # == Logging Out
   #
@@ -98,13 +98,13 @@ ActiveAdmin.setup do |config|
   # will call the method to return the path.
   #
   # Default:
-  config.logout_link_path = :destroy_admin_user_session_path
+  config.logout_link_path = :sign_out_path

   # This setting changes the http method used when rendering the
   # link. For example :get, :delete, :put, etc..
   #
   # Default:
-  # config.logout_link_method = :get
+  config.logout_link_method = :delete

   # == Root
   #
・・・

6. root_pathの設定

手順5. まで完了したらhttp://localhost:3000/adminにアクセスしてみましょう。

localhostやポート番号の3000は自身の環境に合わせてください


アクセスすると下記のエラーが発生すると思います。

NameError (undefined local variable or method `root_path' for #<Admin::AlcoholsController:0x0055a9592f3d40>):

tmp/bundler/ruby/2.3.0/gems/sorcery-0.10.3/lib/sorcery/controller.rb:98:in `not_authenticated'
tmp/bundler/ruby/2.3.0/gems/sorcery-0.10.3/lib/sorcery/controller.rb:25:in `require_login'
・・・

これは認証が必要なページに未認証でアクセスした時にsorceryがroot_pathにリダイレクトしようとしているのですが、root_pathが設定されていないのでこのエラーが発生しています。


これを解決するにはconfig/routes.rbでrootの設定をすればいいです。

未認証でアクセスした場合はログイン画面に遷移して欲しいのでログイン画面のアクションを指定します。

  • config/routes.rb
Rails.application.routes.draw do
  ActiveAdmin.routes(self)

  resources :sessions, only: %i(new create)
  delete 'sign_out', to: 'sessions#destroy'

  root to: 'sessions#new'

  ・・・
end

これで、未認証状態でhttp://localhost:3000/adminにアクセスした時にログイン画面へ遷移させることができるようになりました。

【番外】config/routes.rbにrootを設定する以外の方法

上記でconfig/routes.rbにrootを設定する方法を紹介しましたが、rootがログイン画面なのは何かしっくり来ません。(私だけでしょうか?)

そんな場合はapplication_controller.rbのでsorceryが定義したnot_authenticatedをオーバーライドします。


  • app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
   ・・・

  # override sorcery not_authenticated method
  def not_authenticated
    redirect_to new_session_path
  end

  ・・・
end

7. 確認

rails consoleなどでユーザを作成してからログインを行いましょう。ログイン後activeadminのダッシュボード画面が表示されると思います。

※ログアウトも問題なくできるはずです


以上で完了です。