rails left joins inner includes active ruby-on-rails activerecord ruby-on-rails-3 named-scope arel

ruby-on-rails - left - ruby rails active record



¿Cómo abarca las asociaciones de ActiveRecord en Rails 3? (6)

¿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 las extensiones de asociación en comparación con los métodos de clase o ámbitos es que tiene acceso a las partes internas del proxy de asociación:

proxy_association.owner devuelve el objeto del que forma parte la asociación. 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#association-extensions

Tengo un proyecto de Rails 3. Con Rails 3 llegó Arel y la capacidad de reutilizar un alcance para construir otro. Me pregunto si hay una forma de usar ámbitos 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 tenga en cuenta mis columnas de permisos para que los registros (incluso aquellos a los que se accede a través de una relación) se filtren.

Actualmente, en Rails 3, default_scope (incluidos los parches que he encontrado) no proporcionan un medio viable de pasar un proceso (que necesito para el enlace variable tardío). ¿Es posible definir un has_many en el que se puede pasar un alcance con nombre?

La idea de reutilizar un alcance 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 la codificación implícita de ese alcance nombrado 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 tarde. Preferiría usar un enfoque Arel (si hay uno), pero usaría cualquier opción viable.

Como me refiero al usuario actual, no puedo confiar en las condiciones que no se evalúan en el último momento posible, como por ejemplo:

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


En lugar de telescopios, acabo de definir los métodos de clase, lo que ha funcionado muy bien

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


Puede utilizar el método de fusión para fusionar ámbitos de diferentes modelos. Para más detalles busque fusión en esta railscast


Si solo intenta obtener las órdenes del usuario, ¿por qué no usa la relación?

Suponiendo que se puede acceder al usuario actual desde el método current_user en su controlador:

@my_orders = current_user.orders

Esto asegura que solo se mostrarán los pedidos específicos de un usuario. También puede hacer combinaciones anidadas arbitrariamente para obtener recursos más profundos mediante el uso de joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where(''level3s.id'' => X)


Te sugiero que eches un vistazo a "Los ámbitos con nombre están muertos"

El autor explica qué tan poderoso es Arel :)

Espero que ayude

EDIT # 1 de marzo de 2014

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

Sin embargo, sigo recomendando personalmente no exponer el alcance de Arel a una capa superior (ya sea un controlador o cualquier otra cosa que acceda directamente a los modelos), y para hacerlo necesitaría:

  1. Cree un alcance y exhíbalo a través de un método en su modelo. Ese método sería el que expone al controlador;
  2. Si nunca expones tus modelos a tus controladores (para que tengas algún tipo de capa de servicio sobre ellos), entonces estás bien. La capa anticorrupción es su servicio y puede acceder al alcance de su modelo sin preocuparse demasiado por cómo se implementan los ámbitos.

Yo uso 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