0

私はチームツリーハウスコースに従っています。リファクタリングされていることの 1 つは、投稿されるステータスの user_id を、現在ログインしているユーザーのみに制限する機能です。投稿するにはログインする必要があるというフィルターを既に確立しているため、ここで実行しようとしているのは、ユーザーが別のユーザーとしてステータスを投稿できないようにすることだけです。

ユーザーhas_many :statuses

これは、コントローラーで Statuses#create メソッドがどのように見えるかです

 def create
    @status = Status.new(params[:status])

    respond_to do |format|
      if @status.save
        format.html { redirect_to @status, notice: 'Status was successfully created.' }
        format.json { render json: @status, status: :created, location: @status }
      else
        format.html { render action: "new" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

私たちが変えていることは、@status = Status.new(params[:status])

現在、User モデルに Devise を使用しているため、現在のユーザーは次のように表されます。current_user

次の変更が作成されます。@status = current_user.statuses.new(params[:status])

この声明は私を混乱させます

ここで何が起こっているのかを理解しようとしました。

以下は、Rails コンソールを使用したプロセスの調査です。

irb(main):003:0> User.first.statuses
  User Load (0.5ms)  SELECT "users".* FROM "users" LIMIT 1
  Status Load (0.1ms)  SELECT "statuses".* FROM "statuses" WHERE "statuses"."user_id" = 2
=> [#<Status id: 2, content: "this is a test status", created_at: "2013-07-23 20:53:35", updated_at: "2013-07-23 20:53:35", user_id: 2>, #<Status id: 3, content: "test2", created_at: "2013-07-23 21:34:59", updated_at: "2013-07-23 21:34:59", user_id: 2>]
irb(main):004:0> User.first.statuses.class
  User Load (0.6ms)  SELECT "users".* FROM "users" LIMIT 1
  Status Load (0.3ms)  SELECT "statuses".* FROM "statuses" WHERE "statuses"."user_id" = 2
=> Array
irb(main):005:0> User.first.statuses.new.class
  User Load (0.5ms)  SELECT "users".* FROM "users" LIMIT 1
=> Status(id: integer, content: text, created_at: datetime, updated_at: datetime, user_id: integer)
irb(main):006:0> Array.new
=> []
irb(main):007:0> Array.new.class
=> Array
irb(main):008:0> 

User.first.statuses から返されたオブジェクトのクラス (予想どおり) が配列であることがわかったのに、配列で呼び出された .new のクラスが新しいステータスを生成したのはなぜですか。これはどのように/なぜ機能するのですか? Array.new を呼び出すと、配列が取得されます。配列オブジェクトに対して new を呼び出していませんか?

4

1 に答える 1

2

トリックは、current_user.statuses配列を返さないことです。確かに配列のように見えますが、試してみると配列であることがわかりますが、それはcurrent_user.statuses.class遅延評価された後です。実際に返されるのはオブジェクトであり、Rails コンソールでActiveRecord::Relation試すことでこれを自分で確認できます。current_user.statuses.fooのようなメッセージが表示されますundefined method 'foo' for #<ActiveRecord::Relation:0x007fba7d603918>。ActiveRecord::Relation は、ActiveRecord の非常に便利な部分であり、オブジェクトを連鎖させている間、スコープを管理し、別の ActiveRecord::Relation ではない何かを要求するまで、実際にはデータベースに対してクエリを実行しません。

Ryan Bates は彼のRailscastでこれをかなりよく説明しています。ActiveRecord::Relation と Arelについて議論しているブログでは、この点についても議論しています。

于 2013-07-27T02:37:57.857 に答える