Rails,如何渲染模型中的视图/部分

在我的模型中,我有:

after_create :push_create 

我push_create我需要呈现一个视图。 我试图这样做:

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

这愤怒的轨道,因为它不喜欢我在模型中呈现一个视图,但我需要在那里。

错误:

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

build议? 我应该把它渲染到别的地方吗? 或者我该如何在模型中渲染设置内容? 谢谢

妥善解决

那么,他们是对的。 你真的必须在控制器中进行渲染 – 但是从模型中调用控制器是公平的。 幸运的是,Rails 3中的AbstractController比我想像的更容易。 我结束了一个简单的ActionPusher类,就像ActionMailer一样工作。 也许我会变得雄心勃勃,并且总有一天会把它变成一个合适的gem,但是这对我鞋子里的其他人来说应该是一个好的开始。

我从这个链接得到了最多的帮助: http : //www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/

在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 

在app / pushers / users_pusher.rb中。 我猜这个要求可能会更加全球化吗?

 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 

现在在我的模型中,我可以这样做:

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

然后你会想要一个部分的,例如app / views / users_pusher / add_notice.js.haml,这可能很简单:

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

我想你并不需要在PUSABLE内部类和最后的.push调用中做到这一点,但我想让它看起来像ActiveMailer。 我的用户模型也有一个pusher_key方法,为每个用户创build一个频道 – 但这是我第一次使用Pusher的第一天,所以我不能肯定地说这是正确的策略。 还有更多需要充实的东西,但这对我来说已经足够了。

祝你好运!

(这是我的第一个答案,留下来,因为它可能有助于某人)

我已经掌握了一个解决scheme的总体概况。 像这样,在你的模型中:

 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 

这绝对是工作 – 模板正在渲染,并成功地在客户端获取eval()。 我打算清理它,几乎可以肯定地移动render_anywhere更通用的地方,并可能尝试这样的事情

我可以看到推送将需要自己的模板,调用通常可用的模板,我可能会尝试将它们集中在一个地方。 一个不错的小问题是,我有时在我的partials中使用controller_name,就像点亮一个菜单项,但显然我必须采取不同的策略。 我猜我可能不得不做一些事情来获得更多的帮手,但我还没有得到。

成功! 万岁! 这应该回答你的问题,我的 – 我会添加更多的细节,如果它似乎稍后适当。 祝你好运!!!!

为了清楚起见,原来的一个小时前没有回答

我没有答案,但这个及时的问题值得更多的澄清,我希望能得到接近我的答案,帮助问:)

我面临同样的问题。 为了更清楚地解释,Pusherasynchronous地发送内容到连接的用户浏览器。 一个典型的用例是向用户显示来自另一个用户的新消息。 使用Pusher,您可以将消息推送到接收者的浏览器,以便他们在login后立即收到通知。有关Pusher可以做什么的真正的演示,请查看http://wordsquared.com/。;

您可以发送任何您喜欢的数据,例如JSON哈希来解释您喜欢的方式,但发送RJS将非常方便,就像在客户端上的任何其他ajax调用和eval()一样。 这样,您可以(例如)为您的菜单栏呈现模板,将其全​​部更新,或者只显示给用户的新消息计数,使用所有相同的部分来保持它的骨干。 原则上,您可以从发送者的控制器渲染部分,但也没有多大意义,甚至可能没有请求,例如,可以由cron作业触发,或者其他事件,比如股价变化。 发件人控制器不应该知道 – 我喜欢让我的控制器饥饿饮食;)

这可能听起来像是对MVC的违反,但实际上并不是这样 – 它确实应该用ActionMailer之类的东西来解决,但是与应用程序的其余部分共享助手和分支。 我知道在我的应用程序中,我想发送一个Pusher事件同时(或者不是)一个ActionMailer调用。 我想根据用户A的事件渲染用户B的任意部分。

这些链接可能会指出解决scheme:

最后一个看起来是最有希望的,提供这个诱人的片段:

 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 

正如上面另一张海报所提供的链接一样 。

我会报告回来,如果我有什么工作

tl;博士:我也是!

我只是这样做:

 ApplicationController.new.render_to_string(partial: 'messages/any', locals: { variable: 'value' }) 

您可以直接使用ActionView并将部分渲染为string,而无需使用控制器。 例如,我发现这个模式对创build封装一些javascript代的模型很有用。

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

然后,把你的_test.html.erb放在你的视图文件夹中,然后试试看!

Rails 5的方式

一个控制器之外的 Rails 5 渲染变得相当简单,因为实现了 render控制器类的方法:

 # render template ApplicationController.render 'templates/name' # render action FooController.render :index # render file ApplicationController.render file: 'path' # render inline ApplicationController.render inline: 'erb content' 

在控制器之外调用render ,可以通过assigns选项分配实例variables,并使用控制器中的其他可用选项:

 ApplicationController.render( assigns: { article: Article.take }, template: 'articles/show', layout: false ) 

请求环境可以通过默认选项来定制

 ApplicationController.render inline: '<%= users_url %>' # => 'http://default_host.com/users' ApplicationController.renderer.defaults[:http_host] = 'custom_host.org' # => "custom_host.org" ApplicationController.render inline: '<%= users_url %>' # => 'http://custom_host.org/users' 

或者通过初始化一个新的渲染器来明确

 renderer = ApplicationController.renderer.new( http_host: 'custom_host.org', https: true ) renderer.render inline: '<%= users_url %>' # => 'https://custom_host.org/users' 

希望有所帮助。

我相当肯定你所寻找的答案在于Crafting Rails应用程序 ,其中Jose Valim详细介绍了如何以及为什么要从你的db直接渲染视图

对不起,我还没有更多的帮助,因为我今天晚上刚开始阅读。

可能会 在这里find一些帮助 – 这是一个关于做这种事情的博客文章,尽pipe使用的方法不同于你的方法

这样做的“正确”方式是以序列化的forms(json)推送一个对象,然后一旦收到事件就让视图处理它。 也许你想用Handlebars来渲染对象。

编辑:我最初写了如何,尽pipe我的答案,我会按照你的例子。 但是我刚刚意识到,在推送通知时,您的方法存在一个巨大的问题。

在你的问题,你正在推送通知给一个用户。 对我来说,我正在向一组用户广播。 所以我打算用一个“current_user”的推定来呈现html,以及与之相关的所有内容(例如逻辑,权限等)。 这是没有BUENO,因为每个推送通知将由不同的“当前用户”接收。

因此,实际上,您只需要发回数据,并让每个单独的视图处理它。

你应该调用控制器的所有渲染方法。 因此,在这种情况下,您可以通知控制器该对象已经创build,然后控制器可以呈现该视图。 而且,因为你只能渲染一次,所以我认为你可以在调用渲染之前等待所有的服务器端操作完成。

渲染方法在ActiveController类及其子代上定义。 本质上,你不能在模型上访问它,也不是一个类方法,所以你没有控制器的实例就不能使用它。

我从来没有尝试实例化一个控制器来expression一个局部的简单string的明确目的,但是如果你能把你的手放在一个控制器上,那么render_to_string似乎就是要走的路。

我会告诉你,如果你要走这条路,你就把RoR从“Rails”中拿走了。 这是对MVC的一种违反,并且从根本上说是糟糕的程序devise。这并不意味着我认为你是一个坏人:P有时候生活会让我们离开轨道,可以这么说。

我无法详细说明驱使你这样做的细节,但我强烈build议你重新考虑你的方法。

我为此创造了一个要点。
我需要类似的东西,模型不一定(或在我的情况下)通过控制器更新,所以逻辑不能坐在那里。

创build一个基于服务器推送的控制器:
https://gist.github.com/4707055