私のproject.rbモデルでは、動的変数でスコープを作成しようとしています:
scope :instanceprojects, lambda {
where("projects.instance_id = ?", current_user.instance_id)
}
次のエラーが表示されます。
undefined local variable or method `current_user' for #<Class:0x102fe3af0>
コントローラ内のどこにアクセスできるかcurrent_user.instance_id
...モデルがアクセスできない理由とアクセスする方法はありますか?また、これは上記のようなスコープを作成する適切な場所ですか、それはコントローラーに属しますか?
すでに指摘したように、これはあまり意味がありません。 current_userはモデルロジックにまったく属していません。コントローラーレベルで処理する必要があります。
ただし、コントローラーからパラメーターを渡すだけで、そのようなスコープを作成できます。
scope :instanceprojects, lambda { |user|
where("projects.instance_id = ?", user.instance_id)
}
これで、コントローラーで呼び出すことができます。
Model.instanceprojects(current_user)
すでに受け入れられている答えは、これを達成するための本当に正しい方法を提供します。
ただし、これはスレッドセーフバージョンのUser.current_user
騙す。
class User
class << self
def current_user=(user)
Thread.current[:current_user] = user
end
def current_user
Thread.current[:current_user]
end
end
end
class ApplicationController
before_filter :set_current_user
def set_current_user
User.current_user = current_user
end
end
これは期待通りに機能しますが、ここでは基本的にグローバル変数を定義しているため、ダーティと見なすことができます。
ライアン・ベイツは、この種の戦略を実装するためのかなり安全な方法を示しています このrailscastで
これは有料のエピソード(私に投票しないでください!)でもできます ソースコードを無料で閲覧
ここで彼はcurrent_tenant
メソッドを作成しますが、代わりにcurrent_user
を簡単に置き換えることができます。
コードの重要な部分は次のとおりです...
#application_controller.rb
around_filter :scope_current_tenant
private
def current_tenant
Tenant.find_by_subdomain! request.subdomain
end
helper_method :current_tenant
def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
#models/tenant.rb
def self.current_id=(id)
Thread.current[:tenant_id] = id
end
def self.current_id
Thread.current[:tenant_id]
end
その後、モデルで次のようなことができます...
default_scope { where(tenant_id: Tenant.current_id) }
スコープを使用する必要はありません。モデルに適切な関連付けを設定している場合、コントローラーに配置された次のコードがトリックを実行するはずです。
@projects = current_user.instance.projects