2012-03-21 2 views
1

Мой вопрос касается методов контроллера (возможно, из внешнего класса), которые работают с переменными экземпляра. Я часто использую before_filter в контроллерах, чтобы установить некоторые переменные, например .:RoR: экземпляры переменных в методах контроллера

class DocumentController < ApplicationController 
    before_filter :fetch_document 

    def action 
    @document.do_something 
    end 

    private 

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

Я работаю над проектом, в котором несколько контроллеров разделят некоторое функциональные возможности, скажем, редактирование документа. Моя первая мысль заключалась в том, чтобы извлечь соответствующие методы и получить их из application_controller.rb или отдельного модуля. Но потом я заметил, что я пишу код, который выглядит следующим образом:

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

    def do_something_to_document 
    @document.do_something 
    end 

Это оттеняет предупредительные колокола: do_something_to_document существу предполагая существование @document, а не принимать его в качестве аргумента. Это, по твоим мудрым мнениям, плохое кодирование? Или я параноик?

Предполагая, что это вопрос, я вижу два общих подхода к ее решению:

  1. Проверить экземпляра вар и залог, если это не набор:

    def do_something_to_document 
        raise "no doc!" unless @document 
        [...] 
    end 
    
  2. вызова действия с экземпляр вар в качестве аргумента:

    def do_something_to_document(document) 
        [...] 
    end 
    

2 выглядит лучше, потому что он скрывает контекст вызывающего объекта. Но do_something_to_doc будет вызываться только контроллерами, которые уже настроили @document, и использование @document в качестве аргумента метода приводит к накладным расходам на создание объекта. (Правильно?) 1 кажется хакерским, но должен охватывать все случаи.

Я склонен идти с 1 (при условии, что я прав насчет проблемы с производительностью), хотя просмотр списка методов, ссылающихся на таинственные экземпляры, дает мне ульи. Мысли? Дайте мне знать, если я могу быть более ясным. (И, конечно, если это отвечает где-то я не видел, просто мне точку в правильном направлении ...)

Спасибо, -Erik

ответ

0

Если вам действительно нужен документ в разных контроллерах, я бы что-то вроде этого:

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

Спасибо. Мне нравится этот подход. – Erik

+0

Только что заметили: этот документ-гарант никогда не будет выполнен. document wont be nil, потому что find() может вызвать ошибку, если ничего не найдено. – Deradon

+0

Да. Однако общая идея. Благодарю. – Erik

0

Как @variable являются сессии/экземпляр переменной вам получит исключение Nil в do_something_to_document метод.

Первый код в порядке, потому что before_filter всегда будет загружать ваш @document.

Я предлагаю вам написать что-то вроде этого

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

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

где do_something_to_document находится в контроллере (если нет, то не использовать Params [: ID], даже если вы знаете, что вы можете получить доступ к этим глобальным, использование другой явный параметр). || = вещь, будет зависеть, что вы вызываете базу только один раз по запросу.

+0

'@document || = Document.find (doc_id) ' Выполнение такого кэширования с передачей аргументов может быть очень сложным. Он всегда будет возвращать тот же @document во время запроса, даже если изменяется «doc_id». – Deradon

Смежные вопросы