Domanda

Ho un progetto Rails 3. Con Rails 3, è venuto Arel e la possibilità di riutilizzare un ambito per costruire un altro. Mi chiedo se c'è un modo per utilizzare gli ambiti in cui la definizione di un rapporto (ad esempio un "has_many").

Ho record che hanno le colonne di autorizzazione. Vorrei costruire un default_scope che prende le mie colonne autorizzazione in considerazione in modo che i record (anche quelli a cui si accede attraverso un rapporto) vengono filtrati.

Al momento, in Rails 3, default_scope (comprese le patch che ho trovato) non forniscono un mezzo praticabile di superamento di un proc (che mi serve per ritardo variabile vincolante). E 'possibile definire un has_many in cui un ambito denominato può essere passato?

L'idea di riutilizzare un ambito denominato sarebbe simile:

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

o implicitamente di codifica che di nome ambito nel rapporto sarà simile:

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

Sto semplicemente cercando di applicare default_scope con l'associazione tardiva. Io preferirei usare un approccio Arel (se ce n'è uno), ma vorrei utilizzare qualsiasi opzione praticabile.

Dal momento che mi riferisco per l'utente corrente, non posso contare su condizioni che non sono valutati all'ultimo momento possibile, come ad esempio:

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

Soluzione

vi consiglio di dare un'occhiata a "scopi Named sono morti "

L'autore spiega lì quanto potente Arel è:)

Spero che ti aiuto.

EDIT # 1 marzo 2014

Come qualche stato commenti, la differenza è ormai una questione di gusto personale.

Tuttavia, ho ancora personalmente consiglio per evitare di esporre la portata di Arel ad uno strato superiore (essendo un controller o qualsiasi altra cosa che accedono direttamente i modelli), e così facendo richiederebbe:

  1. Crea un ambito, ed esporlo attraverso un metodo nel modello. Tale metodo sarebbe quello di esporre al controllore;
  2. Se non avete mai esporre i vostri modelli ai controller (in modo da avere un qualche tipo di livello di servizio su di loro), allora sei bene. Lo strato anti-corruzione è il vostro servizio e si può accedere al campo di applicazione del modello senza preoccuparsi troppo di come ambiti di applicazione.

Altri suggerimenti

Come sulle estensioni di associazione?

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)

UPDATE: Vorrei far notare il vantaggio di estensioni di associazione a differenza di metodi di classe o ambiti è che si ha accesso alle parti interne del proxy dell'associazione:

  

proxy_association.owner restituisce l'oggetto che l'associazione è una parte di.   proxy_association.reflection restituisce l'oggetto di riflessione che descrive l'associazione.   proxy_association.target restituisce l'oggetto associato per belongs_to o has_one, o la raccolta di oggetti associati per has_many o has_and_belongs_to_many.

Maggiori dettagli qui: http://guides.rubyonrails.org/association_basics.html# association-estensioni

Invece di ambiti Ho appena la definizione di classe-metodi, che ha lavorato grande

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

io uso qualcosa di simile:

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

È possibile utilizzare merge il metodo al fine di fondere ambiti da diversi modelli. Per la ricerca di maggiori dettagli per unione in questo Railscast

Se stai solo cercando di ottenere gli ordini degli utenti, perché non è sufficiente utilizzare il rapporto?

Presumendo che l'utente attuale è accessibile dal metodo current_user nel controller:

@my_orders = current_user.orders

Questo assicura solo viene fornita ordini specifici di un utente. È anche possibile fare in modo arbitrario annidato si unisce per ottenere le risorse più profonde utilizzando joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top