61 votes

Rails, Comment rendre une vue / partielle dans un modèle

Dans mon modèle j'ai:

 after_create :push_create
 

Je push_create j'ai besoin de rendre une vue. J'essaie de faire ça comme ça:

   def push_event(event_type)
    X["XXXXX-#{Rails.env}"].trigger(event_type, 
      {
        :content => render( :partial =>"feeds/feed_item", :locals => { :feed_item => self })
      }
    )
  end
 

Cela agace les rails car il n’aime pas que je rende une vue dans le modèle, mais j’en ai besoin ici.

Erreur:

 NoMethodError (undefined method `render' for #<WallFeed:0x1039be070>):
 

Suggestions? Devrais-je le rendre quelque part ailleurs? Ou comment puis-je effectuer un rendu dans le modèle pour définir le contenu? Merci

66voto

stephan.com Points 756

la bonne solution

Eh bien, "ils" sont à droite. Vous avez vraiment à faire le rendu dans un contrôleur mais c'est le jeu juste à appeler le contrôleur à partir d'un modèle! Heureusement, AbstractController dans Rails 3, il est plus facile que je ne le pensais. J'ai fini par faire un simple ActionPusher de classe, de travail tout comme ActionMailer. Peut-être que je vais obtenir ambitieux et faire de cette un bon bijou un jour, mais cela devrait servir comme un bon début pour quelqu'un d'autre dans mes chaussures.

J'ai eu le plus de l'aide de ce lien: http://www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/

dans lib/action_pusher.rb

class ActionPusher < AbstractController::Base
  include AbstractController::Rendering
  include AbstractController::Helpers
  include AbstractController::Translation
  include AbstractController::AssetPaths
  include Rails.application.routes.url_helpers
  helper ApplicationHelper
  self.view_paths = "app/views"

  class Pushable
    def initialize(channel, pushtext)
      @channel = channel
      @pushtext = pushtext
    end

    def push
      Pusher[@channel].trigger('rjs_push', @pushtext )
    end
  end
end

dans app/poussoirs/users_pusher.rb. Je suppose que le besoin pourrait aller quelque part plus global?

require 'action_pusher'

class UsersPusher < ActionPusher
  def initialize(user)
    @user = user
  end

  def channel
    @user.pusher_key
  end

  def add_notice(notice = nil)
    @notice = notice
    Pushable.new channel, render(template: 'users_pusher/add_notice')
  end
end

Maintenant, dans mon modèle, je peux faire ça:

after_commit :push_add_notice

private

def push_add_notice
  UsersPusher.new(user).add_notice(self).push
end

et puis vous aurez besoin d'un partiel, par exemple app/views/users_pusher/add_notice.js.haml, qui pourrait être aussi simple que:

alert('#{@notice.body}')

Je suppose que vous n'avez pas vraiment besoin de le faire avec des États d'intérieur de la classe et de l' .pousser à la fin, mais je voulais la faire ressembler à ActiveMailer. J'ai aussi un pusher_key méthode sur mon modèle d'utilisateur, de faire un canal pour chaque utilisateur, mais ce c'est mon premier jour avec quelque chose comme Pusher, donc je ne peux pas dire à coup sûr si c'est la bonne de la stratégie. Il n'y a plus à être précisées, mais c'est assez pour moi pour commencer.

Bonne chance!

(c'était mon premier brouillon de la réponse, de le laisser, car il pourrait aider quelqu'un)

J'ai le plan général d'une solution de travail. Comme cela, dans votre modèle:

after_create :push_new_message

private

def render_anywhere(partial, assigns = {})
  view = ActionView::Base.new(ActionController::Base.view_paths, assigns)
  view.extend ApplicationHelper
  view.render(:partial => partial)
end  

def push_new_message
  pushstring = render_anywhere('notices/push_new_message', :message_text => self.body)
  Pusher[user.pusher_key].trigger!('new_message', pushstring)
end

c'est certainement de travail - le modèle est rendu, et obtient la fonction eval()'ed sur le côté client avec succès. J'ai l'intention de le nettoyer, presque à coup sûr en render_anywhere quelque part plus général, et probablement essayer quelque chose comme ceci

Je peux voir qui pousse auront besoin de leurs propres modèles, l'appel de la généralement disponibles, et je peut essayer de recueillir tous dans un seul endroit. Un joli petit problème est que j'utilise parfois nom_controller dans mes partiels, comme à la lumière d'un élément de menu, mais je vais bien sûr prendre une tactique différente là. Je devine que je pourrais avoir à faire quelque chose pour obtenir plus d'aides disponibles, mais je ne l'ai pas encore là.

Succès! Hourra! Cela devrait répondre à votre question, et la mienne - je vais ajouter plus de détails si cela semble approprié plus tard. Bonne chance!!!!

d'origine non-réponse à partir d'une heure à gauche pour plus de clarté

Je n'ai pas de réponse, mais ce en temps opportun question mérite plus de précisions, et je suis l'espoir d'obtenir plus près à ma réponse en l'aidant à se demander :)

Je suis confrontée au même problème. Pour expliquer un peu plus clairement, Poussoir de manière asynchrone envoie le contenu à un utilisateur connecté au navigateur. Un cas d'utilisation typique serait une montrant à l'utilisateur ils ont un nouveau message d'un autre utilisateur. Avec Poussoir, vous pouvez envoyer un message au récepteur du navigateur, afin qu'ils obtiennent une notification immédiate si ils sont connectés. Pour une très belle démonstration de ce que le Poussoir peut faire, découvrez http://wordsquared.com/

Vous pouvez envoyer toutes les données que vous aimez, comme un JSON de hachage pour interpréter la manière dont vous l'aimez, mais il serait très pratique pour envoyer des RJS, comme avec tout autre appel ajax et de la fonction eval() sur le côté client. De cette façon, vous pouvez (par exemple) de rendre le modèle de votre barre de menu, la mise à jour dans son intégralité, ou tout simplement le nouveau nombre de message affiché à l'utilisateur, en utilisant tous la même partiels pour le garder SEC. En principe, vous pourriez rendre l'partielle de l' expéditeur du contrôleur, mais cela ne fait pas beaucoup de sens non plus, et il pourrait même ne pas être une demande, il pourrait être déclenché par une tâche cron, par exemple, ou d'un autre événement, comme une action de changement de prix. L'expéditeur contrôleur devrait juste pas savoir à ce sujet - je tiens à garder mes contrôleurs sur un régime de famine ;)

Il peut sembler comme une violation de la MVC, mais c'est vraiment pas - et il ne devrait vraiment être résolu avec quelque chose comme ActionMailer, mais le partage des aides et harmoniques avec le reste de l'application. Je sais que dans mon application, je voudrais envoyer un Poussoir événement au même moment (ou au lieu) d'un ActionMailer appel. Je veux rendre un arbitraire partielle pour l'utilisateur B basée sur un événement de l'utilisateur A.

Ces liens peuvent pointer vers la voie d'une solution:

La dernière semble la plus prometteuse, en offrant cette alléchante extrait:

def render_anywhere(partial, assigns)
  view = ActionView::Base.new(Rails::Configuration.new.view_path, assigns)
  ActionView::Base.helper_modules.each { |helper| view.extend helper }
  view.extend ApplicationHelper
  view.render(:partial => partial)
end

Comme ce lien fourni par une autre affiche ci-dessus.

Je vais rendre compte si je reçois quelque chose de travail

tl;dr: moi aussi!

60voto

Kevin Points 1618

Peut-être que c'est plus facile qu'avant, mais je fais juste ceci:

 ApplicationController.new.render_to_string(:partial => 'messages/any', :object => im)
 

Render_to_string doit être appelé depuis un contrôleur. Par conséquent, j'instancie une nouvelle copie du contrôleur générique.

24voto

hsgubert Points 1031

Vous pouvez utiliser directement ActionView et rendre des partiels en chaîne sans passer par un contrôleur. Je trouve ce modèle utile pour créer des modèles qui encapsulent une génération de javascript, par exemple.

 html = ActionView::Base.new(Rails.configuration.paths['app/views']).render(
  :partial => 'test', 
  :formats => :html,
  :handlers => :erb,
  :locals => { :fake_variable => 'fake_value' }
)
 

Ensuite, mettez simplement votre _test.html.erb dans votre dossier de visualisation et essayez-le!

2voto

marflar Points 13293

Je suis assez sûr que les réponses que vous cherchez se trouvent dans l'Artisanat Applications RailsJose Valim va dans les détails sur comment et pourquoi vous voulez le rendre vues directement à partir de votre base de données

Désolé je ne peux pas être de plus d'aide encore parce que j'ai juste commencé à le lire moi-même ce soir.

Vous pourriez trouver de l'aide ici - c'est un billet de blog à propos de faire ce genre de chose, mais en utilisant les différentes méthodes que la vôtre

2voto

Peter P. Points 973

la "bonne" façon de le faire est de pousser un objet en forme sérialisée(json), et ensuite avoir le point de vue de traiter avec elle une fois que l'événement est reçu. Peut-être que vous souhaitez utiliser Guidon pour restituer l'objet.

Edit: j'ai d'abord écrit sur la façon dont, en dépit de ma réponse, je vais suivre votre exemple. Mais je viens de réaliser il y a un ÉNORME piège avec votre approche quand il s'agit de notifications push.

Dans votre problème, vous faites des notifications push à un seul utilisateur. Pour moi, j'ai de radiodiffusion à un ensemble d'utilisateurs. Alors que j'allais pour rendre le code html avec une présomption de "current_user" et tout ce qui vient avec elle(par exemple, la logique, les autorisations, etc). Ce n'est PAS BUENO comme chaque notification push sera reçu par un autre "utilisateur actuel".

Donc, vraiment, vous avez besoin simplement de renvoyer les données, et permettre à chaque individu de vue de la gérer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X