2010-08-21 8 views
1

표준 레일 애플리케이션이 있습니다.RoR : 정의되지 않은 메소드 'url_for'for nil : NilClass

팁을 만들었 으면 해당 팁에 관심이있는 각 사용자에 대한 메시지를 만들고 싶습니다.

이것은 간단할까요?

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 #<TipObserver:0xb75ca17c> (NoMethodError) 

좋아, 그래서 UrlWriter 방법에 액세스해야 TipObserver이

그래서, 우리는 팁 옵저버로 시작 ...해야한다. 이 문제를 해결하는 것은 상당히 간단해야합니다.

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

는 이제 실행 및 출력 (!) : 작동

Hello dave18, a new tip: /tips/511 

우수함! 글쎄, 정말 우리는 그것이 클릭 가능한 링크가되기를 바랍니다. 다시 말하지만, 그것은 쉽지 않을까요?

tip_observer.rb:13:in `after_save': undefined method `link_to' for #<TipObserver:0xb75f7708> (NoMethodError) 

좋아, 그래서 UrlHelper 방법에 액세스해야 TipObserver이 시간 :

link_to_tip = link_to tip.name, tip_path(tip) 

오류. 이 문제를 해결하는 것은 상당히 간단해야합니다.

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) 

흠,이 주변에 명백한 방법이없는이 다른 순서로 포함하려고 할 수 있습니다. 하지만 일부 clever-clogs suggestion that Sweepers are the same as 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(tip) => nil 

이 좋아 잘 내가 그렇게 아마 우리는 다른 방향에서이 공격 할 수있다, 어떻게 문제를 해결하기 위해 아무 생각이 없다 그러므로

tip_path => nil 

과 : 콘솔에 추가 조사는 것을 알 수있다. 콘텐츠를 erb 템플릿으로 옮기고 Message를 렌더링하면됩니다.본문을보기로 설정하면 두 가지 이점이 있습니다. 첫째, "보기"내용이 올바른 위치에 놓이기 때문에 이러한 * _ 경로 문제를 피할 수 있습니다.

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 

오류 :

는 그래서 after_save 방법을 변경할 수 있습니다

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 

큰 그래서 우리는 무엇 이건 우리가 오류와 함께 종료합니다. 나는 성공없이 template_instance 안에 default_url_options을 할당하는 많은 방법을 시도했다.

지금까지는 "Railsy"라는 느낌이 거의 들지 않았습니다. 사실 아주 어렵다고 느낍니다.

그래서 제 질문은 :

  • 오전 나는 둥근 구멍에 스퀘어 페그를 얻으려고? 그렇다면 이 기능을 에 제공하기 위해 아키텍처를 어떻게 조정해야합니까? 그 어떤 것이 존재하지 않는다고 믿을 수 없어 다른 웹 사이트.
  • Observer 또는 Sweeper를 사용하는 것을 포기해야합니까?
  • MessagesController, 을 통해 새 메시지를 작성해야합니까? 그렇다면 Observer/Sweeper에서 직접 MessagesController를 직접 호출하고 을 여러 번 호출 할 수 있습니까?

팁 조언이나 제안은 매우 감사하게 생각할 것입니다. 저는 며칠 동안이 벽돌 벽에 머리를 대고 살기를 천천히하고 있습니다.

TIA

키스

+0

그럼 우리는 – ktec

+0

신 새끼 고양이를 죽인다 ...가는 꽤 좋은 내 정신 상태를 고려했습니다, 나는 이것을 달성하기 위해 깨끗한 방법이 기대했다 - 내가 사전 구성된 객체를 만드는 것이 그렇게 어렵다고 믿을 수 없습니다. FactoryGirl이나 Machinist와 같은 것을 원한다고 느낀다는 뜻입니다. 그리고 그들은 문자열을보기로 렌더링하는 데 도움이되지 않을까요? – s84

답변

2

그럼 당신은 당신의 접근 방식은 매우 레일-Y 아니라고 맞다. 모델, 컨트롤러 및 뷰 메소드를 의도하지 않은 방식으로 혼합하려고 시도하고 있는데, 이는 항상 약간 불안정합니다.

경로를 시작한 경우 link_to 문제를 포기했을 것입니다 ("Rails 방식"이 아닌 것으로 인정합니다). 직접 HTML 링크를 코딩했습니다. 그래서 link_to_tip = link_to tip.name, tip_path(tip)link_to_tip = '<a href="#{tip_path(tip)}">#{tip.name}</a>이 될 것입니다 .- 만약 당신이 하나를 찾고 있다면, 빠르고 더러운 해결책입니다 .-)

그러나 비표준 방식으로 작업하기를 원할 때까지 레일즈는 꽤 깔끔합니다. 그렇다면 당신을 물들 일 수 있습니다 :-)

문제는 당신이 쓰지 않고 거기에 있으면 안되는 메시지 모델에 텍스트를 저장하고 있다는 것입니다. 메시지 모델은 belong_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)}" %> 
+0

감사 스테파노 롤, 지금까지 1 새끼 고양이를 잃고, – ktec

+0

당신이 설명하는 거의 동일한 문제에 직면했을 때의 해결책을 알려주기 위해 내 게시물을 업데이트했습니다 .- 코드 외에도 메시지 소스가 될 수있는 각 모델에 message_link 메서드를 추가했습니다 보기를 단순화합니다 (소스 유형을 확인할 필요가 없음). – StefanOS

+0

StefanO에게 다시 한 번 감사드립니다. 나는 당신이 한 일을 이해하지만 정말로 Message 클래스와 Tip 클래스 사이의 연결을 생성하고 싶지는 않습니다. 단지 링크를 성립시키기 위해서입니다, 그것은 확실히 Railsy가 아닙니다 !! 내 응용 프로그램 팁을 포함하지 않는 여러 가지 다른 통신 메시지를 사용합니다. 누구나 다른 제안을 제시 할 수 없다면 http://facebooker.rubyforge.org/svn/trunk/facebooker/lib/facebooker/ facebooker 라이브러리의 Publisher 클래스와 비슷한 것을 작성하려고합니다. rails/publisher.rb – ktec

관련 문제