2012-08-04 14 views
12

Quiero mostrar una lista de enlaces de afiliados, cada uno etiquetado para identificar al usuario actual. Sería simple en HTML, pero estamos escribiendo una API, por lo que el resultado es JSON.Rieles: reemplazando as_json por valor dinámico: ¿hay alguna manera más inteligente?

Lo tengo funcionando, pero parece demasiado complicado. ¿Es este el mejor enfoque?

Mi modelo, AffiliateLink contiene un campo (el HTML sin formato del enlace) que voy a transformar y generar al vuelo agregando un token. Tengo un método de modelo que produce la sustitución - que no es trivial porque usamos múltiples afiliados y cada uno tiene una regla de transformación especial que este método capaz de hacer:

def link_with_token(user_token) 
    # some gnarly code that depends on a lot of stuff the model knows 
    # that returns a proper link 
end 

para conseguir mi html enlace correcto en JSON I han hecho estas cosas:

  • suman attr_accessor :link_html para modelar
  • añadir un método de instancia para establecer el nuevo descriptor de acceso

.. .

def set_link_html(token) 
    self.link_html = link_with_tracking_token(token) 
end 
  • override as_json en el modelo, la sustitución de la html_code original con link_html

...

def as_json(options = {}) 
    super(:methods => :link_html, :except => :html_code) 
end 
  • iterar sobre la colección devuelta en el método controlador para hacer la transformación

...

def index 
    @links = Admin::AffiliateLink.all # TODO, pagination, etc. 

    respond_to do |format| 
    format.html # index.html.erb 
    format.json do 
     @links.each do |link| 
     link.set_link_html(account_tracking_token) 
     end 
     render json: @links 
    end 
    end 
end 

Este parece ser un montón de cosas que hacer para conseguir mi transformación teensy-weensy hecho. Sugerencias útiles (relacionadas con este problema y no con otros aspectos del código, que están en proceso de cambio) son bienvenidas.

+0

opciones como 'Rabl' o simplemente utilizar realmente una plantilla para contribuir a que su' json' vs reemplazando el método 'as_json' ¿fuera de la cuestión? – nowk

+0

He incursionado con RABL pero parece presentar más obstáculos (especialmente como resultado de documentos limitados). Algún día, solo leeré el código y descubriré cómo usarlo. Por ahora, 'as_json' parece ser suficiente. –

Respuesta

18

1) Una solución rápida a su problema (como se demuestra here):

affiliate_links_controller.rb

def index 
    @links = Admin::AffiliateLink.all # TODO, pagination, etc. 

    respond_to do |format| 
    format.html # index.html.erb 
    format.json do 
     render json: @links.to_json(:account_tracking_token => account_tracking_token) 
    end 
    end 
end 

AffiliateLink.rb

# I advocate reverse_merge so passed-in options overwrite defaults when option 
# keys match. 
def as_json(options = {}) 
    json = super(options.reverse_merge(:except => :html_code)) 
    json[:link_with_token] = link_with_token(options[:account_tracking_token]) 
    json 
end 

2) Una solución más duro, si realmente estás escribiendo una API:

  1. Ver this article describir su problema.
  2. Ver the gem que los autores hicieron como una solución.
  3. Consulte this railscast sobre el uso de la gema.

3) Y, por último, la solución conveniente. Si tiene una relación modelo conveniente, esto es limpio:

Pretendiendo AffiliateLink belongs_to :user. Y suponiendo que user_token es un atributo accesible de User.

AffiliateLink.rb

# have access to user.user_token via relation 
def link_with_token 
    # some gnarly code that depends on a lot of stuff the model knows 
    # that returns a proper link 
end 

def as_json(options = {}) 
    super(options.reverse_merge(:methods => :link_with_token, :except => :html_code)) 
end 

affiliate_links_controller.rb

def index 
    @links = Admin::AffiliateLink.all # TODO, pagination, etc. 

    respond_to do |format| 
    format.html # index.html.erb 
    format.json do 
     render json: @links 
    end 
    end 
end 
+0

¡Buena respuesta! Gracias. –

+0

Ah me alegro de poder ayudar – anxiety

+0

@anxiety podría ser bueno mencionar también ActiveModel :: Serializers, que son una adición reciente a Rails - ver: https://blog.engineyard.com/2015/active-model-serializers, ver también: http://railscasts.com/episodes/409-active-model-serializers – Tilo

Cuestiones relacionadas