RoR: экземпляры переменных внутри методов контроллера - PullRequest
1 голос
/ 21 марта 2012

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

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. Проверьте наличие экземпляра var и bail, если он не установлен:

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

    def do_something_to_document(document)
      [...]
    end
    

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

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

Спасибо, -Erik

Ответы [ 2 ]

0 голосов
/ 21 марта 2012

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

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 голосов
/ 21 марта 2012

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

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

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

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], даже если вызнаю, что вы можете получить доступ к этому глобальному, используйте другой явный параметр).|| = вещь, гарантирует, что вы вызываете базу только один раз по запросу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...