我想创建将为用户生成通知的自定义类。我的问题是:如何通过link_to
Rails帮助程序生成通知文本中的资源链接?
我所尝试的内容:
来自this的相关说明以及"如何在模型"中使用link_to
:包括ActionView::Helpers::UrlHelper
和Rails.application.routes.url_helpers
到Maker
等类似答案} class并且有以下错误,当我尝试使用create_text
时出现在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>'
我的代码是:
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
答案 0 :(得分:2)
我想出了如何做到这一点。该错误是由不正确的url_for
调用引起的,应该使用参数only_path
调用,如下所示:
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
或者作为替代方案,应在enviropment配置文件中设置default_host
参数。
答案 1 :(得分:1)
我建议使用Presenter Pattern的变体(它允许您在Plain Old Ruby Object中调用link_to
之类的方法)。 Ryan Bates在这个话题上有一个很好的RailsCast。这大致是我如何做到的......
首先,我要创建一个PresenterBase
类(我在presenters
目录中保留一个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
请注意,我传递了controller
,然后通过view_context
访问了controller.view_context
。然后,我覆盖method_missing
,将未知方法(例如link_to
)发送到view_context
(具有link_to
方法)。
然后你的Notifies::Maker
看起来像这样:
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
最后,您的控制器可能看起来像这样:
class FooController < ApplicationController
def foo_method
@model = some_method_to_set_model
@kind = some_method_to_set_kind
Notifies::Maker.run(self)
end
end
我没有测试,所以它可能是错误的。但是,也许它会有所帮助。