web-dev-qa-db-ja.com

Modelでselfを使用する場合

質問:Railsのモデルでselfを使用する必要があるのはいつですか?

モデルの1つにsetメソッドがあります。

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    self.active_flag = val
    self.save!
  end
end

これを行うと、すべてが正常に機能します。ただし、これを行うと:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

Active_flagの値は変更されず、サイレントに失敗します。誰か説明できますか?

重複を見つけることはできませんが、誰かがそれを見つけたとしてもそれは問題ありません。

68
varatis

メソッドを呼び出しているインスタンスでアクションを実行するときは、selfを使用します。

このコードで

class SocialData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

Active_flagと呼ばれるまったく新しいスコープのローカル変数を定義し、渡された値に設定します。何にも関連付けられていないため、メソッドが存在しなかったように終了するとすぐに破棄されます。

self.active_flag = val

ただし、真新しい変数ではなく、active_flagと呼ばれる独自の属性を変更するようインスタンスに指示します。それが動作する理由です。

62
DVG

これは、スコーピングが原因で発生します。メソッドの内部にいるときにsetのような新しい変数をしようとすると:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
  end
end

Set_active_flag内に存在する新しい変数を作成しています。実行が完了するとすぐに消え、self.active_flag(実際のインスタンス変数)は変更されません。

[〜#〜] however [〜#〜](これは私にとって混乱の原因でした):readのようなRubyのインスタンス変数:

class SomeData < ActiveRecord::Base
  def whats_my_active_flag
    puts active_flag
  end
end

実際にself.active_flag(実際のインスタンス変数)が返されます。


理由:

Rubyはnilを返さないようにできることをします。

  1. 最初に「active_flagwhats_my_active_flagのスコープ内に存在しますか?
  2. 答えが「ノープ」であることを検索して認識しているため、SomeDataのインスタンスにp 1レベルジャンプします
  3. 同じことをもう一度尋ねます:「active_flagはこのスコープ内に存在しますか?
  4. 答えは「はい」であるため、「yaのために何かを得ました」と表示され、それが返されます。

ただし、active_flag内でwhats_my_active_flagを定義し、それを要求した場合は、再度手順を実行します。

  1. active_flagwhats_my_active_flagのスコープ内に存在しますか?
  2. 答えは「はい」なので、その値を返します

どちらの場合も、明示的に指示しない限り、changeself.active_flagの値にはなりません。

この動作を説明する簡単な方法は、「あなたを失望させたくない」とnilを返すことです。

同時に、「変更するつもりのないデータを台無しにしたくない」ので、インスタンス変数自体を変更しません。

お役に立てれば!

54
Yuval Karmi

Setterメソッドを使用していることを確認し、新しい変数をスコープしないようにします。 RubyとARの使用法の詳細は、しばしば人をつまずかせます(もう1つは、インスタンス変数の(誤った)使用法です)。

pdate_attributes! がすでに存在することに注意してください。

また、 toggle! もあります。これは、フラグへのインターフェースに応じて、さらに良い場合があります。

1
Dave Newton

active_flag = val Rubyがローカル変数を定義していると考えた場合、最良の方法はself.active_flag = valです。もし手に入れたら、send(:active_flag=, val)がも動作します。

0
fangxing