Rails 3 devise, el usuario actual no es accesible en un Modelo?


En mi proyecto.modelo rb, estoy tratando de crear un ámbito con una variable dinámica:

scope :instanceprojects, lambda { 
    where("projects.instance_id = ?", current_user.instance_id)
} 

Obtengo el siguiente error:

undefined local variable or method `current_user' for #<Class:0x102fe3af0>

Donde en el controlador puedo acceder current_user.instance_id... ¿Hay alguna razón por la que el modelo no puede acceder a él y una manera de obtener acceso? Además, ¿es este el lugar correcto para crear un ámbito como el anterior, o pertenece al controlador?

Author: Smar, 2010-09-18

4 answers

Esto no tiene mucho sentido, como ya señalaste. El current_user no pertenece a la lógica del modelo en absoluto, debe ser manejado en el nivel del controlador.

Pero aún puede crear un ámbito como ese, simplemente pase el parámetro desde el controlador:

scope :instanceprojects, lambda { |user|
    where("projects.instance_id = ?", user.instance_id)
} 

Ahora puedes llamarlo en el controlador:

Model.instanceprojects(current_user)
 73
Author: mdrozdziel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-24 08:39:23

La respuesta ya aceptada proporciona una manera realmente correcta de lograr esto.

Pero aquí está la versión segura de User.current_user truco.

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

Esto funciona como se espera, sin embargo, se puede considerar sucio, porque básicamente definimos una variable global aquí.

 30
Author: Michał Szajbe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-21 10:10:42

Ryan Bates presenta una forma bastante segura de implementar este tipo de estrategia en este railscast

Este es un episodio pagado (¡no me votes!) pero puedes buscar el código fuente de forma gratuita

Aquí crea un método current_tenant, pero usted podría sustituir fácilmente current_user en su lugar.

Aquí están los bits clave de código...

#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

Entonces en el modelo se puede hacer algo como...

default_scope { where(tenant_id: Tenant.current_id) }
 8
Author: Lumbee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-21 17:27:17

No es necesario utilizar ámbitos. Si ha establecido las asociaciones apropiadas en los modelos, el siguiente fragmento de código colocado en el controlador debería hacer el truco:

@projects = current_user.instance.projects
 0
Author: sampi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-18 19:32:50