/ / RoR: variabili di istanza all'interno dei metodi del controller - ruby-on-rails, coding-style

RoR: variabili di istanza all'interno dei metodi del controller: ruby-on-rails, stile di codifica

La mia domanda riguarda i metodi del controller (possibilmente inclusi da una classe esterna) che funzionano con le variabili di istanza. Uso spesso un before_filter nei controller per impostare determinate variabili, ad esempio:

class DocumentController < ApplicationController
before_filter :fetch_document

def action
@document.do_something
end

private

def fetch_document
@document = Document.find(params[:id])
end
end

Ho lavorato a un progetto in cui alcunii controller condivideranno alcune funzionalità, ad esempio la modifica dei documenti. Il mio primo pensiero è stato quello di estrarre i metodi pertinenti e ottenerli da application_controller.rb o da un modulo separato. Ma poi ho notato che stavo scrivendo un codice simile a questo:

  def fetch_document
@document = Document.find(params[:id])
end

def do_something_to_document
@document.do_something
end

Questo fa scattare campanelli d'allarme:do_something_to_document essenzialmente presuppone l'esistenza di @document, piuttosto che prenderlo come argomento. Secondo le tue saggi opinioni, questa è una cattiva pratica di programmazione? O sono paranoico?

Supponendo che sia un problema, vedo due approcci generali per affrontarlo:

  1. Controlla l'istanza var e bail a meno che non sia impostata:

    def do_something_to_document
    raise "no doc!" unless @document
    [...]
    end
    
  2. Chiama l'azione con l'istanza var come argomento:

    def do_something_to_document(document)
    [...]
    end
    

2 ha un aspetto migliore, perché nasconde il contesto dil'oggetto chiamante. Ma do_something_to_doc verrà chiamato solo dai controller che hanno già impostato @document, e prendere @document come argomento del metodo comporta l'overhead della creazione dell'oggetto. (Giusto?) 1 sembra un hacker, ma dovrebbe coprire tutti i casi.

Sono propenso ad andare con 1 (ammesso che abbia ragionesul problema delle prestazioni), anche se vedere un elenco di metodi che fanno riferimento a variabili di istanze misteriose mi dà degli alveari. Pensieri? Fammi sapere se posso essere più chiaro. (E ovviamente, se si risponde a questa domanda da qualche parte non l'ho visto, indicami la giusta direzione ...)

Grazie, -Erik

risposte:

0 per risposta № 1

Se hai davvero bisogno di documenti in controller diversi, farei qualcosa del genere:

class ApplicationController < ActionController::Base
private
def document
@document ||= Document.find(params[:document_id])
end
end

class FooController < ApplicationController
before_filter :ensure_document, :only => [:foo]

def foo
document.do_something
end

private
# TODO: not sure if controller_name/action_name still exists
def ensure_document
raise "#{controller_name}##{action_name} needs a document" unless document
end
end

0 per risposta № 2

Poiché @variable è una variabile di sessione / istanza, otterrai un'eccezione nulla in do_something_to_document metodo.

Il primo codice va bene, perché before_filter caricherà sempre il tuo @document.

Ti suggerisco di scrivere qualcosa del genere

def fetch_document(doc_id)
@document ||= Document.find(doc_id)
end

def do_something_to_document
my_doc = fetch_document(params[:id])
end

dove do_something_to_document è nel controller (in caso contrario, non utilizzare params [:id], anche se sai di poter accedere a questo globale, usa un altro parametro esplicito). La cosa || = assicurerà che chiamerai la base solo una volta su richiesta.