8

con un'applicazione di e-commerce in fase di sviluppo sto cercando di capire il seguente problema: Ho le mie categorie realizzate tramite il plugin awesome_nested_set. Se elenco i miei articoli selezionando una categoria, tutto funziona correttamente, ma per alcuni collegamenti voglio mostrare tutti i prodotti di una categoria e i prodotti delle sue categorie figlio.ottenere tutti i prodotti di categorie e categorie figlio (rails, awesome_nested_set)

qui è il codice di controllo che funziona bene con una sola categoria:

# products_controller.rb 
    def index 
    if params[:category] 
     @category = Category.find(params[:category]) 
     #@products = @category.product_list 
     @products = @category.products 
    else 
     @category = false 
     @products = Product.scoped 
    end 
    @products = @products.where("title like ?", "%" + params[:title] + "%") if params[:title] 
    @products = @products.order("created_at).page(params[:page]).per(params[:per_page] ? params[:per_page] : 25) 
    @categories = Category.all 
    end 

La linea ho commentato fuori è un metodo di supporto me stesso ho scritto nel modello di categoria che restituisce tutti i prodotti della categoria e del suo bambino categorie in un array.

Essa è definita come segue:

# app/models/category.rb 
def product_list 
    self_and_ancestors.to_a.collect! { |x| x.products } 
end 

Ora, quando ho Decommentare questa linea e cerco di selezionare le pause di codice una categoria miei prodotti controller con errori come

undefined method `order' for #<Array:0x1887c2c> 

o

undefined method `page' for #<Array:0x1887c2c> 

perché sto usando l'ordinamento e l'impaginazione e non può più ordinare l'arario.

Qualche idea su come ottenere tutti i prodotti in un elemento di relazione ActiveRecord nel mio controller? grazie

UPDATE

così, quando uso il seguente:

class Category < ActiveRecord::Base 
    acts_as_nested_set 

    attr_accessible :name, :description, :lft, :rgt, :parent_id 

    has_many :categorizations 
    has_many :products, :through => :categorizations 

    attr_accessor :product_list 

    def branch_ids 
     self_and_descendants.map(&:id).uniq 
    end 

    def all_products 
     Product.find(:all, :conditions => { :category_id => branch_ids }) 
    end 


end 

e chiedere al controllore per @category.all_products ottengo il seguente errore:

Mysql::Error: Unknown column 'products.category_id' in 'where clause': SELECT `products`.* FROM `products` WHERE `products`.`category_id` IN (6, 8, 9) 

come farei ottenere tutti i prodotti con questa costellazione?

UPDATE 2

Ok, quindi ho intenzione di iniziare una taglia.

se provo:

def all_products Categorization.find (: all,: condizioni => {: category_id => branch_ids}) fine

ottengo di nuovo undefined method ordine' per # ` Ho bisogno di sapere come posso ottenere tutti i prodotti di una relazione many_to_many come una relazione ActiveRecord.

UPDATE 3

ho messo il codice in questione in un gist https://gist.github.com/1211231

risposta

5

La chiave con awesome_nested_set consiste nell'utilizzare un intervallo nella colonna lft. Ecco un esempio di codice di come lo faccio con un'associazione diretta (articoli categoria has_many)

module Category 
    extend ActiveSupport::Concern 
    included do 
     belongs_to :category 
     scope :sorted, includes(:category).order("categories.lft, #{table_name}.position") 
    end 

    module ClassMethods 
     def tree(category=nil) 
     return scoped unless category 
     scoped.includes(:category).where([ 
      "categories.tree_id=1 AND categories.lft BETWEEN ? AND ?", 
      category.lft, category.rgt 
     ]) 
     end 
    end # ClassMethods 
    end 

Poi da qualche parte in un controller

@category = Category.find_by_name("fruits") 
@articles = Article.tree(@category) 

che troverà tutti gli articoli nelle categorie mele, arance, banane, ecc. ecc. Si dovrebbe adattare questa idea con un join su categorizzazioni (ma sei sicuro di aver bisogno di una relazione molti a molti qui?)

Ad ogni modo proverei questo:

class Product < AR 
     has_many :categorizations 

     def self.tree(category=nil) 
     return scoped unless category 
     select("distinct(products.id), products.*"). 
     joins(:categorizations => :category).where([ 
      "categories.lft BETWEEN ? AND ?", category.lft, category.rgt 
     ]) 
     end 
end 

Fatemi sapere se c'è qualche Gotcha

+0

questo mi dà un errore di sintassi .. . "/Users/frankblizzard/Sites/rails_projekte/sotaca/app/models/product.rb:56: errore di sintassi, imprevisto '}', in attesa di tASSOC scoped.joins (: categorizzazioni => {: categoria}). Dove ([" – tmaximini

+0

wait - penso che funzioni ora (rimosso le parentesi graffe intorno: categoria) - testerà in profondità ora – tmaximini

+0

ok funziona così lontano - l'unico risultato è che ora alcuni articoli appariranno due volte - se ne hanno due categorie figlio associate, ad esempio: so che esiste il metodo "uniq" che risolve i duplicati, ma poi di nuovo ".order" e "paginate" non funzioneranno, dato che trasformano la relazione ActiveRecord in una matrice. gestire i duplicati con questo approccio? – tmaximini

3

Ci sono diversi modi si potrebbe migliorare il vostro codice, ma se siete alla ricerca di tutti i prodotti che appartengono a un categoria e bambini (discendenti) della categoria, allora perché non lo faranno in questo modo:

def branch_ids 
    self_and_descendants.map(&:id).uniq 
end 

def all_products 
    Product.find(:all, :conditions => { :category_id => branch_ids }) 
end 

ho fatto alcune ipotesi qui, ma spero che si ottiene l'idea.

+0

grazie, testeremo questo più tardi e riferiremo – tmaximini

+0

Ciao, scusa per tornare tardi, ma ora ricordo di aver provato qualcosa di simile. Il problema è che non c'è nessuna colonna "ID_categoria" nella tabella prodotti. Ho una relazione has_many: attraverso la "categorizzazione" in quanto un prodotto può avere più di una categoria. ecco perché questa query non funzionerà. Aggiornerò la domanda – tmaximini

+0

Raccogliere tutte le classificazioni_ids invece di category_ids e fare qualcosa di simile come ho descritto sopra o scrivere un ambito denominato che esegue join su un modello coinvolto ... – socjopata

0

Estendere la risposta s' charlysisto, quando si tratta di has_and_belongs_to_many categorie, si scopriranno presto che la prospettiva forza bruta è piuttosto lento ... È necessario una sorta di "middleware" per renderlo più veloce ...

La risposta di socjopata offre un buon approccio su come migliorarlo. Quindi, si utilizza la definizione

def branch_ids 
    self_and_descendants.map(&:id).uniq 
end 

nel category.rb del file (modello).

Quindi, per esempio, nel controller (esempio con impaginazione):

@category = Category.find... # whatever 
branches = @category.branch_ids 
@prodcats = ProductCategory.select('distinct product_id') 
          .where('category_id IN (?)',branches) 
          .order(:product_id) 
          .paginate(page: params[:page], :per_page => 25) 
ids  = @prodcats.map(&:product_id) 
@products = Product.where('id IN (?)', ids) 

Infine, a suo avviso, è necessario una "tecnica" piccolo per avere impaginazione. Si impagina su @prodcats, non @products ...

<%= will_paginate @prodcats %> 
<% @products.each do |product| %> 
    .... 
<% end %> 

Questo approccio è il modo più veloce, QUANDO TRATTARE CON many_to_many, anche se non al 100% politicamente corretto, devo ammettere.

Problemi correlati