Recursividad en los menus de navegación


#1

Hola a todos, tengo lo siguiente en

#application.html.erb
<% @tabs.each do |page| -%>
<li <%= “id=‘current’” if @page && (@page == page ||
@page.parent == page) %>><%= link_to page.navlabel,
view_page_path(page.name
)-%>
<% end -%>
lo que hace el código ruby que esta dentro de

  • es determinar si la
    pagina que esta en el menu de navegación es la “current”

    Esto funciona bien con dos niveles de profundidad, pero si hay más ya no
    se
    aplica el estilo “current” a la pestaña que le corresponde.

    ej.:
    tengo un página de coches (por ejemplo. no es mi caso :slight_smile: )
    mi menu es el siguiente

    1-coches deportivos

    2-coche antiguos
    coches antiguos europeos
    coches antiguos europeos diesel
    coches antiguos europeos gasolina
    coches antiguos americanos

    3-coches familiares

    como veis tengo tres tabs principales (coches deportivos, coches
    antiguos,
    coches familiares). El que interesa es coches antiguos. este tiene dos
    niveles por debajo.
    Bien, en el primer nivel (coches antiguos europeos) , con el código de
    arriba, (coches antiguos) recibe el id=“current”, pero cuando bajamos al
    segundo nivel (coches antiguos europeos diesel ó coches antiguos
    europeos
    gasolina) esto se pierde.

    PREGUNTA: ¿Cómo hago para que no se pierda?

    Gracias


  • #2

    2008/5/27 Andrés gutiérrez removed_email_address@domain.invalid:

    PREGUNTA: ¿Cómo hago para que no se pierda?

    Si estás utiizando acts_as_tree la condición de se podría sustituir por:

  • >

    Pero no te recomendaría aumentar mucho los niveles de tu menú, porque
    por cada nivel hasta las raíces es una nueva consulta a la base de
    datos que ancestors tiene que hacer.

    Suerte.


  • #3

    ya se lo que quiero:
    <% @tabs.each do |page| -%>
    <li <%= “id=‘current’” if @page && (@page == page ||
    @page.parent == page) %>>…
    <% end -%>

    si te fijas, lo que me hace falta es averiguar a cual de las paginas
    padre
    pertenece la pagina en la que me encuentro y una vez sabiendolo, la
    asigno a
    una variable:

    @el_principal_de_mi_pagina_actual
    <% @tabs.each do |page| -%>
    <li <%= “id=‘current’” if @page && (@page == page ||
    @page.parent == page || @el_principal_de_mi_pagina_actual == page )
    %>>…
    <% end -%>

    Espero se entienda, lo que no se es como retroceder desde la pagina que
    estoy hasta saber cual es su tab principal

    y esta variable la meto en las condiciones de arriba para determianr
    cual de
    las principales es la que debe de llevar id=“current”

    El día 27 de mayo de 2008 18:20, Andrés gutiérrez
    removed_email_address@domain.invalid
    escribió:


    #4

    2008/5/27 Andrés gutiérrez removed_email_address@domain.invalid:

    ya se lo que quiero:

    y esta variable la meto en las condiciones de arriba para determianr cual de
    las principales es la que debe de llevar id=“current”

    No sé si exactamente se ajusta a tu problema, no me da tiempo a leer
    todo el hilo, pero ¿no sería mejor que simplemente asignases ids a tus
    tabs y un id o clase al body en cada página? De ese modo solucionas el
    estilado sólo con css. Además de que el identificador del body te dará
    oportunidad de hacer muchas más cosas

    Es decir

    li#foo
    li#bar

    body#body_foo
    body#body_bar

    body#body_foo li#foo, body#body_bar li#bar {
    // Estilos para #current
    }


    Manuel, que
    piensa que eres una excelente persona y medra en torno a
    http://simplelogica.net y/o http://simplelogica.net/logicola/
    Recuerda comer mucha fruta y verdura.


    #5

    No sé si exactamente se ajusta a tu problema, no me da tiempo a leer
    todo el hilo, pero ¿no sería mejor que simplemente asignases ids a tus
    tabs y un id o clase al body en cada página? De ese modo solucionas el
    estilado sólo con css. Además de que el identificador del body te dará
    oportunidad de hacer muchas más cosas

    con esto quieres decir que asigne un id por cada body-bar de cada página
    que
    cree??
    si es esto, no me gusta la idea, ya que lo que estoy haciendo lo estoy
    pillando de un tutorial que pantean la app de tal forma que pueda crear
    todas las paginas
    que quiera, y luego decir si esta pagina es un subpagina o si es una
    principal (paren is NULL)

    El día 27 de mayo de 2008 18:55, Manuel González Noriega <
    removed_email_address@domain.invalid> escribió:


    #6

    Si estás utiizando acts_as_tree la condición de se podría sustituir por:

    No lo utilizo

    Pero no te recomendaría aumentar mucho los niveles de tu menú, porque
    por cada nivel hasta las raíces es una nueva consulta a la base de
    datos que ancestors tiene que hacer.

    ¿cómo lo harias de forma eficiente?

    Tengo que aclarar lo que hago en mi modelo para conseguir “parent”

    #page.rb

    class Page < ActiveRecord::Base
    acts_as_textiled :body
    has_many :subpages, :class_name => ‘Page’, :foreign_key =>
    ‘parent_id’
    belongs_to :parent, :class_name => ‘Page’, :foreign_key =>
    ‘parent_id’

    def self.find_main
        Page.find(:all, :conditions => ['parent_id IS NULL'], :order =>
    

    ‘position’)
    end

    def self.find_main_public
        Page.find(:all, :conditions => ["parent_id IS NULL and admin != 
    

    ?",
    true], :order => ‘position’)
    end
    end

    Como ves Page tienen a sus ancestros en el mismo modelo y esas dos
    funciones
    (find_main y find_main_public) las uso en:

    #application.rb
    before_filter :get_pages_for_tabs

    def get_pages_for_tabs
    if logged_in?
    @tabs = Page.find_main
    else
    @tabs = Page.find_main_public
    end
    end

    De aquí saco @tabs (las generales de la app) para mi layout
    (application.html.erb)
    #application.html.erb
    <% @tabs.each do |page| -%>
    <li <%= “id=‘current’” if @page && (@page == page ||
    @page.parent == page) %>>…
    <% end -%>
    Asi se las que su parent es NULL lo que quiere decir que son las
    principales, las que esta condición no se cumpla, querrá decir que son
    hijas
    de alguna de esta.
    El día 27 de mayo de 2008 18:03, Daniel R. Troitiño <
    removed_email_address@domain.invalid> escribió:


    #7

    Dios!!!
    que bueno eres, me ha funcionado. No se casi nada, pero he conseguido
    que
    funcione!!!
    Te confieso que no he implementado acts_as_tree, porque todavía estoy
    aprendiendo y siguiendo los tutoriales más o menos al pie de la letra,
    pero a veces, me pregunto cosas y quiero saber como se podría hacer.
    Este
    caso es uno de esos casos.
    Te explicaré (aunque seguro que se puede, que tu sabes, se puede hacer
    mejor) como lo he hecho (PARA LA VIDA REAL USARÍA el PLUGIN)
    pero para aprender, esto que he hecho me vale y me sobra.

    Bien, al lio. Siguiendo tu link [1] y no haciendote caso :-), he cogido
    un
    metodo del plugin, el que me interesaba
    1- Lo he pegado en mi application.rb

    before_filter :get_root
    def get_root

    @page = Page.find_by_name(params[:name])
    if @page != NIL
        @root = @page
         @root = @root.parent while @root.parent
         @root
     end
    

    end

    y luego he usado @root en mi application.html.erb
    <% @tabs.each do |page| -%>
    <li <%= “id=‘current’” if @page && (@page == page || @page.parent

    page || @root == page) %>>…
    <% end -%>

    de esta forma tengo los tabs principales siempre iluminados cuando
    navego
    hacia abajo dentro de ellos.

    Gracias, de verdad. Era exactamente lo que quería. Aunque sea una
    porquería
    de codigo, lo importante es que funciona!!!

    Un saludo

    [1]
    http://dev.rubyonrails.org/browser/plugins/acts_as_tree/lib/active_record/acts/tree.rb#L67

    El día 27 de mayo de 2008 21:58, Daniel R. Troitiño <
    removed_email_address@domain.invalid> escribió:


    #8

    2008/5/28 Andrés gutiérrez removed_email_address@domain.invalid:

        @root = @page
         @root = @root.parent while @root.parent
         @root
     end
    

    end

    El método root (o como lo quieras llama) estaría mejor situado en el
    modelo Page. Ahí, en el controlador, no sirve para mucho más que para
    lo que lo utilizas, y ya
    está.

    y luego he usado @root en mi application.html.erb
    <% @tabs.each do |page| -%>
    <li <%= “id=‘current’” if @page && (@page == page || @page.parent ==
    page || @root == page) %>>…
    <% end -%>

    Metiendo el método en el modelo Page esa parte del código te quedaría:

    <% @tabs.each do |page| -%>

  • >...
  • <% end -%>

    Bueno, aún no entiendo bien qué tabs quieres destacar: el que estás,
    el que estás y todos sus antecedentes, el padre de primer nivel… Si
    es esto último únicamente necesitarías la última parte del OR (la de
    @page.root == page), pero lo que estoy un poco seguro de que es
    innecesaria es la de @page.parent == page.

    Suerte.


    #9

    En realidad “sí” estás utilizando acts_as_tree… ¡pero te lo has
    currado a mano! (bueno, excepto un par de cosas adicionales extras que
    tiene acts_as_tree).

    Lo más sencillo, sin casi tener que cambiar nada de tu código va a ser
    que te bajes el plugin acts_as_tree y modifiques un poco tu modelo:

    class Page < ActiveRecord::Base
    acts_as_textiled :body
    acts_as_tree :order => ‘position’

    # Este método no lo he comprobado pero creo que debería funcionar
    def self.public_roots
      with_scope(:find => { :conditions => ['admin != ?', true] }) do
        roots
      end
    end
    

    end

    Y bueno, cambian algunos de tis métodos cambian de nombre: subpages se
    convierte en children, parent sigue como parent, find_main se
    convierte en roots y find_main_public se convierte en public_roots (lo
    he cambiado de nombre para ajustarse a acts_as_tree).

    De esta forma tendrías el método ancestors disponible (a parte de
    root, siblings y self_and_siblings).

    La otra es implementar el método ancestor en tu modelo. La
    implementación del plugin
    http://dev.rubyonrails.org/browser/plugins/acts_as_tree/lib/active_record/acts/tree.rb#L67
    te sirve perfectamente (creo).

    Mi recomendación, aunque implique un poco más de trabajo es que
    utilices el plugin en vez de duplicar su código.

    Suerte.


    #10

    pero lo que estoy un poco seguro de que es
    innecesaria es la de @page.parent == page.

    Ahora que tengo lo de root si claro

    El método root (o como lo quieras llama) estaría mejor situado en el
    modelo Page. Ahí, en el controlador, no sirve para mucho más que para
    lo que lo utilizas, y ya está
    Lo he puesto asi en page.rb
    def root

    @page = Page.find_by_name(params[:name])
    
        @root = @page
         @root = @root.parent while @root.parent
         @root
     end
    

    Pero me da este ERROR:

    undefined local variable or method `params’

    ¿como puedio saber lo que vale @page desde el modelo?

    Antes de ponerlo en Page.rb, lo he usado en el controlador de pages tal
    cual
    lo tenía en applicaton.rb y me ha funcionado, pero en el modelo, me peta

    UN SALUDO


    #11

    perdón , al reves:
    en el controlador :
    Page.root params[:name]

    y en el modelo:

    def root name

    @page = Page.find_by_name(name)

    @root = @page
    @root = @root.parent while @root.parent
    @root
    end

    El mié, 28-05-2008 a las 12:11 +0200, fernando.martinezgil escribió:


    #12

    lo que tienes que hacer, es en le controlador, donde llamas al metodo
    root, pasarle el params como parametro, y en el modelo definir el metodo
    root con un parametro, más o menos así:

    en el modelo :
    Page.root params[:name]

    y en el controlador:

    def root name

    @page = Page.find_by_name(name)

    @root = @page
    @root = @root.parent while @root.parent
    @root
    end

    ten en cuenta que en los modelos no puedes acceder a la variable params,
    pero siempre puedes pasarsela a los metodos como un parametro.
    Suerte.
    El mié, 28-05-2008 a las 11:13 +0200, Andrés gutiérrez escribió:


    #13

    2008/5/28 fernando.martinezgil removed_email_address@domain.invalid:

    @root = @page
    @root = @root.parent while @root.parent
    @root
    end

    No necesitas pasar parámetros de un lado a otro, al fin y al cabo el
    parámetro que mandas es el objeto que recibe el mensaje:

    class Page
    #…
    def root
    root = self
    root = root.parent while root.parent
    root
    end
    #…
    end

    Suerte.


    #14

    Muchas gracias a los dos. Gracias por la lección

    Un saludo

    El día 28 de mayo de 2008 13:01, fernando.martinezgil <
    removed_email_address@domain.invalid> escribió:


    #15

    tienes razón, no tienes que hacer el find pues ya tienes el objeto…
    ni me fije en para que estaba usando el params…
    la próxima vez estaré más atento :wink:
    El mié, 28-05-2008 a las 12:27 +0200, Daniel R. Troitiño
    escribió: