Pregunta

Tengo un proyecto Rails 3. Con Rails 3 llegó Arel y la capacidad de reutilizar un ámbito a construir otro. Me pregunto si hay una manera de utilizar los alcances cuando se define una relación (por ejemplo, un "has_many").

Tengo registros que tienen columnas de permisos. Me gustaría construir un default_scope que toma mis columnas de permisos en cuenta para que los registros (incluso los que se accede a través de una relación) se filtran.

Actualmente, en los carriles 3, default_scope (incluyendo parches que he encontrado) no proporcionan un medio viable de hacer pasar un proc (que necesito para el enlace en tiempo variable). ¿Es posible definir un has_many en el que se puede pasar de un ámbito con nombre?

La idea de la reutilización de un ámbito con nombre se vería así:

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders

o implícitamente que la codificación ámbito con nombre en la relación se vería así:

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}

Simplemente estoy tratando de aplicar default_scope con el enlace en tiempo. Yo preferiría usar un enfoque Arel (si lo hay), pero usaría ninguna opción viable.

Desde que estoy refiriendo al usuario actual, no puedo confiar en condiciones que no son evaluados en el último momento posible, como por ejemplo:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
¿Fue útil?

Solución

Le sugiero que eche un vistazo a "alcances Named están muertos "

El autor explica no lo poderoso que es Arel:)

espero que va a ayudar.

EDITAR nº 1 de marzo de 2014

Como algunos comentarios Estado, la diferencia es ahora una cuestión de gusto personal.

Sin embargo, todavía personalmente recomiendo para evitar exponer el alcance de Arel a una capa superior (por ser un controlador o cualquier otra cosa que acceder directamente a los modelos), y al hacerlo se requerirá:

  1. Crear un ámbito, y exponerla a través de un método en su modelo. Ese método sería el que se expone al controlador;
  2. Si nunca exponga sus modelos a los controladores (por lo que tiene una especie de capa de servicio en la parte superior de ellos), entonces está bien. La capa anti-corrupción es su servicio y se puede acceder al ámbito de su modelo sin tener que preocuparse demasiado acerca de cómo se implementan los ámbitos.

Otros consejos

¿Qué hay de las extensiones de asociación?

class Item < ActiveRecord::Base
  has_many :orders do
    def for_user(user_id)
      where(user_id: user_id)
    end
  end
end

Item.first.orders.for_user(current_user)

ACTUALIZACIÓN: Me gustaría señalar la ventaja de extensiones de asociación en contraposición a los métodos de clase o ámbitos es que usted tiene acceso a la parte interna de la representación sindical:

  

proxy_association.owner devuelve el objeto de que la asociación es una parte de.   proxy_association.reflection devuelve el objeto de reflexión que describe la asociación.   proxy_association.target devuelve el objeto asociado para belongs_to o has_one, o la colección de objetos asociados para has_many o has_and_belongs_to_many.

Más detalles aquí: http://guides.rubyonrails.org/association_basics.html# de asociación-extensiones

En lugar de alcances Me acaban de Definición de clase-métodos, que ha estado trabajando gran

def self.age0 do
  where("blah")
end

utilizo algo como:

class Invoice < ActiveRecord::Base
  scope :aged_0,  lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) }
end 

Puede utilizar fusionar método con el fin de fusionar los ámbitos de diferentes modelos. Para más detalles la búsqueda de Merge en este Railscast

Si usted está tratando de obtener las órdenes del usuario, ¿por qué no sólo tiene que utilizar la relación?

Suponiendo que el usuario actual es accesible desde el método current_user en su controlador:

@my_orders = current_user.orders

Esto asegura que sólo se mostrarán las órdenes específicas de un usuario. Puede también qué arbitrariamente anidados se une para obtener recursos más profundas usando joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top