在我的模特中,我有:
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
这会激怒rails,因为它不像我在模型中渲染视图但我需要它。
错误:
NoMethodError (undefined method `render' for #<WallFeed:0x1039be070>):
连连呢?我应该以某种方式在其他地方呈现它吗?或者我如何在模型中渲染以设置内容?感谢
答案 0 :(得分:65)
嗯,“他们”是对的。你真的必须在控制器中进行渲染 - 但从模型中调用该控制器是公平的游戏!幸运的是,AbstractController 在Rails 3中使它比我想象的容易。我结束了做一个简单的事情 ActionPusher类,就像ActionMailer一样工作。也许我会野心勃勃 有一天它会成为一个合适的宝石,但这应该成为我鞋子里其他人的良好开端。
我从这个链接获得了最多的帮助: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}')
我猜你真的不需要使用Pushable内部类和.push 最后打电话,但我想让它看起来像ActiveMailer。我也有 我的用户模型上的pusher_key方法,为每个用户创建一个频道 - 但是这个 是我和Pusher这样的第一天,所以我不能确定这是否正确 战略。还有更多可以充实,但这足以让我开始。
祝你好运!我已经得到了解决方案的大致轮廓。像这样,在你的模型中:
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_any转移到更通用的地方,并且可能会尝试something like this
我可以看到推送将需要他们自己的模板,调用普遍可用的模板,我可能会尝试在一个地方收集它们。一个不错的小问题是我有时会在部分中使用controller_name,比如点亮一个菜单项,但我显然必须采取不同的策略。我猜我可能需要做一些事情来获得更多帮助,但我还没有到达那里。
成功!万岁!这应该回答你的问题,我的 - 如果以后看起来合适,我会添加更多细节。祝你好运!!!!
我没有答案,但这个及时的问题值得进一步澄清,我希望通过帮助提问来接近我的答案:)
我面临同样的问题。为了更清楚地解释一下,Pusher异步将内容发送到连接的用户浏览器。典型的用例是向用户显示他们有来自其他用户的新消息。使用Pusher,您可以将消息发送到接收者的浏览器,以便他们在登录时立即得到通知。有关Pusher可以做的非常棒的演示,请查看http://wordsquared.com/
您可以发送您喜欢的任何数据,例如JSON哈希,以解释您的喜好,但发送RJS非常方便,就像客户端的任何其他ajax调用和eval()一样。这样,您可以(例如)渲染菜单栏的模板,完整地更新它,或者仅显示给用户的新消息计数,使用所有相同的部分来保持其骨干。原则上,你可以从发送者的控制器中呈现部分,但这也没有多大意义,甚至可能没有请求,它可以由cron作业触发,例如或其他一些事件,如股价变动。发送者控制器不应该知道它 - 我喜欢让控制器保持饥饿状态;)
这可能听起来像是违反MVC,但实际上并非如此 - 而且它确实应该通过ActionMailer之类的东西来解决,但是与应用程序的其余部分共享帮助程序和部分内容。我知道在我的应用程序中,我想在(或代替)ActionMailer调用的同时发送Pusher事件。我想基于来自用户A的事件为用户B渲染任意部分。
这些链接可能指向解决方案:
最后一个看起来最有希望,提供这个诱人的片段:
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
上面另一张海报提供的this link也是如此。
我会报告我是否有工作
tl;博士:我也是!
答案 1 :(得分:57)
我这样做:
ApplicationController.new.render_to_string(partial: 'messages/any', locals: { variable: 'value' })
答案 2 :(得分:27)
在Rails 5中,由于implemented 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
选项分配实例变量,并使用控制器中提供的任何其他选项:
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'
希望有所帮助。
答案 3 :(得分:23)
您可以直接使用ActionView并将部分渲染为字符串而无需控制器。我发现该模式对于创建封装一些javascript生成的模型非常有用。例如。
html = ActionView::Base.new(Rails.configuration.paths['app/views']).render(
partial: 'test',
formats: [:html],
handlers: [:erb],
locals: { variable: 'value' }
)
然后,只需将_test.html.erb
放入您的视图文件夹中即可试用!
答案 4 :(得分:2)
我很确定你所寻找的答案位于Crafting Rails Applications,其中 Jose Valim 详细介绍了如何和为什么您希望直接从数据库中呈现视图
对不起,我还没有更多的帮助,因为我今晚才开始自己阅读。
你可能找到一些帮助here - 这是一篇关于做这类事情的博文,虽然使用的方法不同于你的
答案 5 :(得分:2)
执行此操作的“正确”方法是以序列化形式(json)推送对象,然后在收到事件后让视图处理它。也许您想使用Handlebars来渲染对象。
编辑:我最初写过关于如何,尽管我的回答,我将按照你的例子。但我刚刚意识到推送通知时你的方法存在巨大的问题。
在您的问题中,您正在向一个用户执行推送通知。对我来说,我正在向一组用户广播。因此,我将使用“current_user”的假设以及随之而来的所有内容(例如逻辑,权限等)来呈现html。这是NO BUENO,因为每个推送通知将由不同的“当前用户”接收。
因此,实际上,您需要发送回数据,并让每个视图处理它。
答案 6 :(得分:0)
您应该从控制器调用所有渲染方法。因此,在这种情况下,您可以通知控制器已创建对象,然后控制器可以呈现视图。此外,由于您只能渲染一次,我认为您可以在调用渲染之前等待所有服务器端操作完成。
答案 7 :(得分:0)
渲染方法是在ActiveController类及其后代上定义的。本质上,您无法在模型上访问它,也不是类方法,因此如果没有控制器实例,则无法使用它。
我从来没有尝试实例化一个控制器,只是为了简单地将一个部分字符串化,但是如果你可以得到一个控制器,那么render_to_string似乎就是这样。
我会说,如果你走这条路,你就会把RoR从“Rails”中拿走。这违反了MVC和基本上糟糕的程序设计。这并不意味着我认为你是一个坏人:P有时生活会让我们摆脱困境,可以这么说。
我无法谈论促使你这样做的细节,但我强烈建议你重新考虑你的做法。
答案 8 :(得分:0)
我为此创造了一个要点 我需要类似的东西,模型不一定(或者在我的情况下,永远)通过控制器更新,所以逻辑不能坐在那里。
创建基于服务器推送的控制器:
https://gist.github.com/4707055
答案 9 :(得分:0)
Rails 6.0.0兼容的答案,因为我在寻找解决方案时出现在此页面上:
pipe()