2017-01-20 1 views
0

Je souhaite créer une classe personnalisée qui générera des notifications pour les utilisateurs. Ma question est: comment générer un lien vers la ressource dans le texte de notification via link_to Rails helper?Comment inclure correctement ActionView :: Helpers dans la classe en dehors de ActionController :: Base?

Ce que je alreay essayé:

instructions Suivi de this et des réponses similaires comme « Comment utiliser link_to dans le modèle »: inclus ActionView::Helpers::UrlHelper et Rails.application.routes.url_helpers dans Maker classe et eu erreur follwing, qui apparaît dans la méthode create_text quand je essayez d'utiliser link_to:

EmployeesControllerTest#test_company_vacancy_daily: 
NameError: undefined local variable or method `controller' for #<Notifies::Maker:0x000000069ae218> 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionview-5.0.0.1/lib/action_view/routing_url_for.rb:132:in `optimize_routes_generation?' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:192:in `optimize_routes_generation?' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:172:in `call' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:295:in `block (2 levels) in define_url_helper' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/polymorphic_routes.rb:262:in `handle_model_call' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionview-5.0.0.1/lib/action_view/routing_url_for.rb:116:in `url_for' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/actionview-5.0.0.1/lib/action_view/helpers/url_helper.rb:196:in `link_to' 
    /app/lib/notifies.rb:32:in `block in create_text' 
    /app/lib/notifies.rb:32:in `map!' 
    /app/lib/notifies.rb:32:in `create_text' 
    /app/lib/notifies.rb:38:in `run' 
    /app/test/controllers/notifications_test.rb:167:in `block (2 levels) in <class:EmployeesControllerTest>' 
    /usr/local/rvm/gems/ruby-2.2.5/gems/activesupport-5.0.0.1/lib/active_support/testing/assertions.rb:71:in `assert_difference' 
    /app/test/controllers/notifications_test.rb:166:in `block in <class:EmployeesControllerTest>' 

Et mon code est:

module Notifies 
    class Maker 

    include ActionView::Helpers::UrlHelper 
    include Rails.application.routes.url_helpers 

    def initialize(model, kind) 
     @model = model 
     @kind = kind 

     case @model.class.to_s 
     when 'Company' 
     @to = @model.admin 
     when 'Employee' 
     @to = @model 
     end 
    end 

    def build_list 
     present = Time.now.utc 
     past = present - 24.hours 

     popularities = Popularity.where(to: @model.entity.id).select do |e| 
     e.updated_at.utc.between?(past, present) 
     end 

     popularities.map! { |p| p.from_entity.turn } 
    end 

    def create_text(popularities = build_list) 
     text = 'Those users interested in your contacts: ' 
     popularities.map! { |p| link_to p.full_name, p } 
     text + popularities.join(', ') 
    end 

    def run 
     popularities = build_list 
     text = create_text(popularities) 
     @to.notify(kind: @kind, text: text) if popularities.any? 
    end 
    end 
end 

Répondre

1

J'ai compris comment faire. L'erreur a été provoquée par une utilisation erronée appel url_for, et il doit être appelé avec le paramètre only_path, comme ceci:

def create_text(popularities = build_list) 
    text = 'Those users interested in your contacts: ' 
    popularities.map! do |reciever| 
    link_to reciever.full_name, url_for([reciever, only_path: true]) 
    end 
    text + popularities.join(', ') 
end 

Ou comme un paramètre de remplacement default_host doit être défini dans le fichier de configuration de enviropment.

0

Je vous recommande d'utiliser une variante du modèle Presenter (qui vous permet d'appeler des méthodes telles que link_to dans un objet Plain Old Ruby). Ryan Bates a un bon RailsCast sur le sujet. Voici ce à peu près comment je le ferais ...

D'abord, je voudrais créer une classe PresenterBase (je garde un dossier presenters dans mon répertoire app):

app/presenters/presenter_base.rb 

    class PresenterBase 

    class << self 
     def present(controller)  new(controller).present     end 
    end 

     def initialize(controller) @controller = controller    end 

    private 

     def controller()   @controller        end 
     def view_context()   controller.view_context     end 

     def get_controller_variable(sym) 
     controller.instance_variable_get("@#{sym}") 
     end 

     def method_missing(*args, &block) 
     view_context.send(*args, &block) 
     end 

    end 

Notez que je passe dans le controller , puis accédez au view_context via controller.view_context. Ensuite, je remplace method_missing pour envoyer des méthodes inconnues (comme link_to) au view_context (qui a la méthode link_to).

Ensuite, votre Notifies::Maker pourrait ressembler à ceci:

class Notifies::Maker < PresenterBase 

    class << self 
     def run(controller) new(controller).run end 
    end 

     def run 
     to_notify.notify(kind: kind, text: text) if popularities.any? 
     end 

    private 

     def kind()   @kind ||= get_controller_variable(:kind)  end 
     def model()   @model ||= get_controller_variable(:model) end 
     def past_time()  present_time - 24.hours      end 
     def popularities() @popularities ||= get_popularities   end 
     def present_time() @present_time ||= Time.now.utc    end 

     def to_notify() 
     case model.class.to_s 
     when 'Company' 
      model.admin 
     when 'Employee' 
      model 
     end 
     end 

     def get_popularities 
     Popularity.where(to: model.entity.id).select do |e| 
      e.updated_at.utc.between?(past_time, present_time) 
     end 
     end 

     def text 
     'Those users interested in your contacts: ' << links 
     end 

     def links 
     popularities. 
      map!{ |p| p.from_entity.turn }. 
      map!{ |p| link_to p.full_name, p }. 
      join(', ') 
     end 

    end 

Enfin, votre contrôleur pourrait ressembler à ceci:

class FooController < ApplicationController 

    def foo_method 
     @model = some_method_to_set_model 
     @kind = some_method_to_set_kind 
     Notifies::Maker.run(self) 
    end 

    end 

Je n'ai pas testé, donc il pourrait être buggy. Mais, peut-être que cela aidera.

+1

Merci, mec, mais cela semble être trop complexe pour générer une seule ligne de texte avec des liens, donc j'ai fait quelques recherches de plus et trouvé la réponse, posté ci-dessous. – Max