2011-01-10 7 views
6

estoy usando el método de instancia de modelo t_param para generar una URL de estilo SEOto_param condicional método

def to_param 
    url 
end 

de esa manera puedo generar links a la modelo con path_to_model (modelo) y consultar el modelo con Model.find_by_url (url) Esto funciona bien hasta ahora.

Mi pregunta: Tengo rutas de administrador REPENTINAS para el back-end. ¿De alguna manera puedo hacer que el método to_param reaccione a la ruta por la que es llamado? Porque quiero crear enlaces en el back-end con el parámetro ID y no el parámetro URL. ¿O cuál es el enfoque correcto aquí?

Respuesta

2

Tuve el mismo problema. Un modelo realmente no puede/no debería saber nada sobre los controladores. El trabajo del controlador es determinar qué recurso se solicita y llamar al modelo para acceder a él. Si su AdminController necesita usar la identificación numérica estándar, no querrá tocar to_param.

Como resultado, la solución es bastante simple, y la utilizo en producción.

Suponiendo que hayas asignado un nombre a tus controladores, tendrás un MyModelController y un Admin :: MyModelController, junto con sus ayudantes. En Admin, haz las cosas de la manera estándar. En MyModelController, haga lo siguiente:

En sus acciones de recursos, consulte params[:id] pero trátelo como un enlace permanente (URL).Por ejemplo

def get 
    @my_model = MyModel.find_by_url(params[:id]) 
    ... 
end 

En su MyModelHelper

def my_model_path my_model 
    super my_model.url 
end 

def my_model_url my_model 
    super my_model.url 
end 

Para mí sentía que esto era la mejor manera de "no luchar" rieles y conseguir lo que necesitaba hecho.

Puede haber una manera más inteligente de anular las rutas nombradas. Además, creo que no puede usar helper :all con este enfoque, a menos que compruebe si está en administración o no antes de generar rutas/url.

0

Ésta es una forma de hacerlo ...

class BlogPost 
    def to_param 
    url 
    end 

    # BlogPost.find_by_param("14") => looks for ID 14 
    # BlogPost.find_by_param("foobar") => looks for url "foobar" 
    # BlogPost.find_by_param("14-foobar") => looks for ID 14 (ignores the "-foobar" part) 
    def self.find_by_param(param) 
    if param.to_s =~ /^[0-9]+/ 
     find_by_id param.to_i 
    else 
     find_by_url param.to_s 
    end 
    end 
end 
+0

mismo digo, no me gustaría la ID en el URL porque quiero separar estrictamente las partes internas del modelo de la representación externa a través de la URL ... posible ... –

+0

Esto no pondrá la ID en la URL. Todo lo que hace es darle otro método de clase, BlogPost.find_by_param, que utiliza en lugar de BlogPost.find_by_url, y eso funciona ya sea que le proporcione una ID o una URL. –

2

¿Estás completamente opuesta a la que tiene el ID en la URL? Si no es así, lo que he hecho en el pasado (que también cumple con el objetivo de URLs 'SEO' es la siguiente:

class Person 
    def to_param 
    "#{id}-#{name.parameterize}" 
    end 
end 

Por lo tanto, en lugar de:

http://www.example.com/users/1

que presentamos lo

http://www.example.com/users/1-jerry-seinfeld

Dado que el método String::to_i se detendrá una vez que se encuentra un carácter no entero (es decir,y "1-jerry-seinfeld".to_i ambos devuelven 1), esto significa que también puede hacer:

person = Person.find(params[:id]) 

sin tener que reemplazar cualquiera de sus buscadores (con el beneficio añadido de trabajar en su frontend y backend de su administrador).

+0

Es una buena solución, pero en realidad estoy realmente en contra de tener la ID en la URL porque quiero separar estrictamente las partes internas del modelo de la representación externa a través de la URL. Todavía estoy buscando una solución donde pueda hacer la El método to_param reacciona al contexto si es posible. –

2

Use en su clase de modelo variable @@to_param y método de clase para controlarlo.

Por ejemplo, en el modelo:

class ProductCategory < ActiveRecord::Base 
    @@to_param = true 

    attr_accessible :description, :name, :parent_id 
    has_ancestry 
    has_many :products 
    validates :slug, :uniqueness => true, :presence => true 

    before_validation :generate_slug 

    #Trigger fo 'to_param' method 
    def self.to_param_trigger(test) 
    if (test) 
     @@to_param = true 
    else 
     @@to_param = false 
    end 
    end 

    def to_param 
    if @@to_param 
     slug 
    else 
     id 
    end 
    end 

    def generate_slug 
    self.slug ||= self.ancestors.map {|item| item.name.parameterize}.push(self.name.parameterize).join('/') 
    end 
end 

En el regulador:

class Backend::ProductCategoriesController < Backend::BaseController 
    def index 
    # Disable 'to_param' 
    ProductCategory.to_param_trigger false 
    @categories = ProductCategory 
     .select([:id, :name, :slug]) 
     .select("COALESCE(ancestry, '0') as anctr") 
     .order :anctr, :name 
    end 

    def new 
    end 

    def edit 
    end 
end 

before_filter y otros trucos de ayuda =)

+0

¿Estás seguro de que esto no lo estropeará? Si está configurando una variable de clase, el valor también existirá para todas las clases, por lo que si está ejecutando esto en producción, una vez que habilite to_param_filter, todas las solicitudes tendrán ese valor independientemente del espacio de nombres –

+0

. Además, hay preguntas para casos multiproceso, pero para mi caso bastante simple, esta solución es adecuada – unixs