RoR: неопределенный метод `url_for 'для nil: NilClass

У меня есть стандартное приложение Rails.

Когда создается Совет, я хотел бы создать Сообщение для каждого Пользователя, который заинтересован в этом Наконечнике.

Это звучит просто, верно? Это должно быть ...

Итак, начнем с Tip Observer:

class TipObserver < ActiveRecord::Observer
  def after_save(tip)
    # after the tip is saved, we'll create some messages to inform the users
    users = User.interested_in(tip) # get the relevant users
    users.each do |u|
      m = Message.new
      m.recipient = u
      link_to_tip = tip_path(tip)
      m.body = "Hello #{u.name}, a new tip: #{link_to_tip}"
      m.save!
    end
  end
end

Ошибки:

tip_observer.rb:13:in `after_save': undefined method `tip_path' for # (NoMethodError)

Хорошо, поэтому TipObserver необходим доступ к методам UrlWriter. Это должно быть довольно просто исправить, верно?

class TipObserver < ActiveRecord::Observer
  include ActionController::UrlWriter

Теперь он работает (!) И выводит:

Hello dave18, a new tip: /tips/511

Отлично, что работает !! Ну, вроде как, на самом деле мы хотим, чтобы это была ссылка для кликов. Опять же, это должно быть легко, верно?

link_to_tip = link_to tip.name, tip_path(tip)

Ошибки:

tip_observer.rb:13:in `after_save': undefined method `link_to' for # (NoMethodError)

Хорошо, так что на этот раз TipObserver необходим доступ к методам UrlHelper . Это должно быть довольно просто исправить, верно?

class TipObserver < ActiveRecord::Observer
  include ActionController::UrlWriter
  include ActionView::Helpers::UrlHelper

Ошибки:

whiny_nil.rb:52:in `method_missing': undefined method `url_for' for nil:NilClass (NoMethodError)

Хорошо, кажется, добавление, которое мешало объявлению url_for. Давайте попробуем включить в другом порядке:

class TipObserver < ActiveRecord::Observer
  include ActionView::Helpers::UrlHelper
  include ActionController::UrlWriter

Ошибки:

url_rewriter.rb:127:in `merge': can't convert String into Hash (TypeError)

Хм, очевидного пути к этому нет. Но после прочтения некоторых умных засорений предполагается, что Sweepers такие же, как Observers , но имеют доступ к помощникам по URL. Итак, давайте преобразуем Observer в Sweeper и удалим UrlHelper и UrlWriter.

class TipObserver < ActionController::Caching::Sweeper
  observe Tip
  #include ActionView::Helpers::UrlHelper
  #include ActionController::UrlWriter

Хорошо, это позволяет ему работать, но вот вывод:

Hello torey39, a new tip:

Итак, ошибки нет, но URL не генерируется. Дальнейшие исследования с помощью консоли показывают, что:

tip_path => nil

и, следовательно:

tip_path(tip) => nil

Хорошо, хорошо, я понятия не имею, как решить эту проблему, поэтому, возможно, мы можем атаковать это с другой стороны. Если мы переместим содержимое в шаблон erb и представим Message.body как представление - это дает два преимущества - во-первых, содержимое «Просмотр» помещается в правильное расположение, и это может помочь нам избежать этих проблем * _path.

Итак, давайте изменим метод after_save:

def after_save(tip)
  ...
  template_instance = ActionView::Base.new(Rails::Configuration.new.view_path)
  m.body = template_instance.render(:partial => "messages/tip", :locals => { 
      :user=>user, 
      :tip=>tip
    })
  m.save!
end

Ошибки:

undefined method `url_for' for nil:NilClass (ActionView::TemplateError)

Отлично, но теперь мы снова вернулись к этому кровавому url_for. Так что на этот раз жаловаться на ActionView. Давайте попробуем исправить это тогда:

def after_save(tip)
  ...
  template_instance = ActionView::Base.new(Rails::Configuration.new.view_path)
  template_instance.extend ActionController::UrlWriter

Ошибки:

undefined method `default_url_options' for ActionView::Base:Class

Отлично, что бы мы ни делали, мы получим ошибки. Я испробовал много разных способов присвоения default_url_options внутри template_instance без успеха.

Пока что это не выглядит очень «Railsy», на самом деле это кажется совершенно трудным.

Итак, мой вопрос:

  • Пытаюсь ли я получить квадратный колышек в круглой дыре? Если так, как я должен адаптировать архитектуру, чтобы обеспечить это функциональность? Я не могу поверить это не то, что существует в другие веб-сайты.
  • Должен ли я отказаться от попыток использовать Observer или Sweeper?
  • Должен ли я пытаться создавать новые сообщения с помощью MessagesController, и если да, то как я могу вызвать MessagesController напрямую и Несколько раз изнутри Наблюдателя / Подметальной машины?

Любые советы, советы или предложения будут с благодарностью приняты, я уже несколько дней бьюсь головой об эту кирпичную стену и медленно теряю желание жить.

tia

Кейт

1
задан ktec 21 August 2010 в 21:02
поделиться

1 ответ

Что ж, вы правы в том, что ваш подход не очень похож на Rails. Вы пытаетесь смешивать методы модели, контроллера и представления таким образом, для которого они не предназначены, и это всегда немного шатко.

Если бы я пошел по вашему пути, я бы, вероятно, отказался от проблемы link_to и (я признаю, что это не «путь Rails») закодировал HTML для ссылки вручную. Итак, link_to_tip = link_to tip.name, tip_path (tip) становится link_to_tip = ' # {tip.name} - быстрое и грязное решение, если вы его ищете; -)

Но, по моему опыту, Rails довольно удобен, пока вы не захотите делать что-то нестандартным способом. Тогда он может вас укусить: -)

Проблема в том, что вы пишете и сохраняете текст в своей модели сообщения, которого там быть не должно. Модель сообщения должна own_to Tips , а представление должно отвечать за представление текста сообщения, включая ссылку на подсказку. Если сообщение может относиться к чему-то другому, кроме советов, вы можете создать полиморфную ассоциацию в модели сообщения следующим образом:

belongs_to :source, :polymorphic => true

Модель подсказки будет включать:

has_many :messages, :as => :source

Затем вы делаете это (используя свой код в качестве примера):

m = Message.new
m.source = tip
m.save!

Представление, которое отображает сообщение, затем отвечает за создание ссылки, например:

<%= "Hello #{u.name}, a new tip: #{link_to m.source.name, tip_path(m.source)}" %>
2
ответ дан 2 September 2019 в 21:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: