これは Rails 4.0.0.rc2 で、バージョン管理された API を作成します。
いくつかのフィールドを持つ単純なモデル「ユーザー」があります。コントローラーのshow
アクションで、データベースからフェッチされるフィールドの数を制限したいと思います (プロジェクションの構築)。だから、代わりに
SELECT "users".* FROM "users" ...
発行したい
SELECT id, first_name, last_name, email FROM "users" ...
これは達成できたと思いますが、望ましくない結果が生じました。Rails は2 つのデータベース クエリを発行します。
詳細
その目的のためにscope
、モデルでa を定義しました。
class User < ActiveRecord::Base
...
scope :brief, -> (id) { select('id, first_name, last_name, email').where('id == ?', id) }
end
コントローラーのshow
アクションは次のように定義されます
def show
if derived_version >= 2
@user = User.brief(params[:id])
else
@user = User.find(params[:id])
end
end
(バージョン管理には versioncake を使用)
バージョン 2 では、スコープはプロジェクションの構築に使用されます。バージョン 1 では、リレーションにすべての列が含まれています。
これは機能しますが、Rails はスコープが使用されたときに 2 つのデータベース クエリを発行し、最初のクエリは奇数です。
Started GET "/api/users/2?api_version=2" for 127.0.0.1 at 2013-06-15 19:49:11 +0200
Processing by Api::UsersController#show as JSON
Parameters: {"api_version"=>"2", "id"=>"2"}
User Load (0.1ms) SELECT id, first_name, last_name, email FROM "users" WHERE (id == '2') ORDER BY "users"."id" ASC LIMIT 1
User Load (0.3ms) SELECT id, first_name, last_name, email FROM "users" WHERE (id == '2')
Rendered api/users/show.v2.json.rabl (89.0ms)
Completed 200 OK in 99ms (Views: 92.5ms | ActiveRecord: 1.0ms)
その場合、バージョン1に切り替えると
@user = User.find(params[:id])
実行され、ログは私が期待するとおりです:
Started GET "/api/users/2?api_version=1" for 127.0.0.1 at 2013-06-15 20:03:56 +0200
Processing by Api::UsersController#show as JSON
Parameters: {"api_version"=>"1", "id"=>"2"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "2"]]
Rendered api/users/show.v1.json.rabl (1.1ms)
Completed 200 OK in 6ms (Views: 4.5ms | ActiveRecord: 0.3ms)
select().where() をコントローラーのアクションに直接入れるなど、いくつかのバリエーションを試しましたshow
が、結果は常に同じです: select()、OR where() OR select().where を使用する場合() Rails は 2 つのクエリを生成します。
ですから、最後の質問をする前に、私は Rails の専門家ではないことを付け加えておく必要があります。
質問
Rails が実際にこれら 2 つのデータベースクエリを実行するという仮定は正しいでしょうか?
2 つのクエリを発行する正当な/説得力のある理由はありますか?