1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel で Eager Loading させてたら artisan:refresh がコケた

Last updated at Posted at 2019-06-24

前提

  • Laravel 5.7
  • PostgreSQL
  • laravel-permissionUser に対するパーミッション周りの実装を実施。
    • User から Role に対する MorphToMany のリレーションを持たせた。
    • User は Global Scope で roles に対する Eager Loading を実施するようにしてある。

起きたこと

artisan migrate:refresh をしたら以下のログと共に失敗して、それ以降 artisan コマンド自体がコケるようになりました。

In Connection.php line 664:

  SQLSTATE[42P01]: Undefined table: 7 ERROR:  relation "roles" does not exist
  LINE 1: ...as_roles"."model_type" as "pivot_model_type" from "roles" in...
                                                               ^ (SQL: select "roles".*, "model
  _has_roles"."model_id" as "pivot_model_id", "model_has_roles"."role_id" as "pivot_role_id", "
  model_has_roles"."model_type" as "pivot_model_type" from "roles" inner join "model_has_roles"
   on "roles"."id" = "model_has_roles"."role_id" where "model_has_roles"."model_id" in (1, 2, 3
  ) and "model_has_roles"."model_type" = App\User and "roles"."deleted_at" is null and "deleted
  _at" is null)

原因

処理は全部追えておらず推測を含むので、間違っているかもしれません。

  • User::boot() 内で roles に対して Eager Loading をさせた事で User を参照する時に roles テーブルの存在が前提になってしまっていた。
  • artisan 実行時に AuthServiceProvider で記述している Gate::define 等により User モデルが呼ばれるので、 roles テーブルも参照される。
    • AuthServiceProvider が呼ばれてるのは config/app.php によるもの?
  • しかし直前に migrate:refreshroles テーブルが既に削除されてるので無理…となっていた。

対応

該当のスコープ内で必要なテーブルの有無をチェックするようにしたら解消し、 migrate:refresh も無限に実行できるようになりました。

app/Scopes/WithRolesScope.php
class WithRolesScope implements Scope
{
    public function apply(Builder $builder, Model $model)
    {
        if ($this->isExistRolesTable()) {
            $builder->with('roles');
        }
    }

    protected function isExistRolesTable()
    {
        $schemaName = config('database.connections.pgsql.schema');
        $rolesTableName = config('permission.table_names.roles');
        $rows = DB::select('SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = ? AND table_name = ?)', [$schemaName, $rolesTableName]);
        return $rows[0]->exists;
    }
}

これがスマートなやり方かどうかは分からない…。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?