QA@IT

PostgreSQLのPG::UndefinedColumn: ERROR:について

4404 PV

PostgreSQLをDBにしてRailsアプリを作成中です。

  • PostgreSQL9.3

以下のような現象をご存知でしたら教えて下さい。

内容

RailsのActiveRecordを通してSQLを実行した時に以下のエラーが出る。

PG::UndefinedColumn: ERROR:  column products.* does not exist
LINE 1: SELECT  "products"."*"

上記の通り、*でエラーが出ます。例ではProductモデルをつかってますが、
Product.allというシンプルなメソッドでも発生します。

rails consoleから接続中にも現象は発生し、consoleを起動し直すと解消します。
解消するのであまり気にしていなかったのですが、

ローカルの環境だけではなく、AWSでのRDSでも発生したのでActiveRecordの問題かと思い
質問させていただきました。

調べてみるべきポイントなどでも結構ですのでご教授をお願い致します。

  • エラー時のSQLはアスタリスクが"で囲まれて作成されています。

    ```
    SELECT
    "products" . "*"
    ```

    コンソールなどで同じクエリをto_sqlなどで取得すると、

    ```
    SELECT
    "products" . *
    ```

    となります。
    -

回答

自己回答になります。

gem squeelを使用して以下の様なスコープをモデルに記述していた。

# productモデル
scope :index_select, -> {
    select{[self.*]}.
    select{[category.name.as(category_name), kind.name.as(kind_name)]}
}

この部分のselect{[self.*]}部分が、 "products". "*"に変換され、エラーとなっておりました。
しかし、"products". *としてSQLが作成される場合と、エラー時のダブルクォーテーションで囲われる時の違いがわからずじまいです。

rails consoleでProduct.allとした場合にも上記の現象が発生した時もありますので、他に原因がありえるかもしれませんが。以下のように書き直すと、今のところ問題なく動作しています。

# productモデル
scope :index_select, -> {
    select('products.*').
    select{[category.name.as(category_name), kind.name.as(kind_name)]}
}

結局

  • production環境で確実に発生する
  • developmentのコンソールでもまれに発生する
  • アプリコードの特定の部分を変更すると発生しなくなる(session_helper.rb)

など不可解な条件が多々ありましたが、gem squeelに依存するものとして、
Arelに移行していきたいと思います。

編集 履歴 (0)

更に補足で申し訳ないのですが、

production 環境で設定ファイルで挙動が変わる

  • config.active_record.migration_error = :page_load

をproduction.rbに追記するとエラーが出ない

エラーが発生する際のコードが判明

#helperのメソッド
  def current_user
    remember_token = User.encrypt(cookies[:remember_token])
    @current_user ||= User.select('*').find_by(remember_token: remember_token)
    #selectを何かしら指定すると発生する、以下のコメントアウトのコードの場合はエラーが出ない
    #@current_user ||= User.find_by(remember_token: remember_token)
  end
  • webrickのサーバをON/OFFすることで挙動が変わる(本エラーの発生有無)
  • Productモデルに限らず、他のモデルのSQLでもエラーが出る

調査の糸口でも構いませんのでご教授お願い致します

編集 履歴 (0)

補足です。

エラー時のSQLはアスタリスクが"で囲まれて作成されています。

SELECT
          "products" . "*"

コンソールなどで同じクエリをto_sqlなどで取得すると、

SELECT
          "products" . *

となります。

編集 履歴 (0)
  • production環境で確実に発生します。
    developmentではリロードしていると解消します。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。