我意识到这是针对MVC主体和所有,但是如何访问类中包含的模块中的控制器名称/方法?
module DocumentHTMLBoxes
extend ActiveSupport::Concern
included do
def icon_or_text(variable)
if controller.action_name == 'send'
"<b>#{variable.name.capitalize}</b> #{variable.text}\n"
else
variable.format!
end
end
end
end
如何在模块中访问controller
和/或controller.action_name
?
答案 0 :(得分:3)
在Rails中,view_context
对象包含来自控制器的所有ivars,并包含所有帮助程序。它还提供对会话,cookie和请求的访问。在渲染模板时,它是隐式self
。
模型无法访问视图上下文 - 这是一种有意识的设计,因为它可以很好地分离关注点。
如果要打破封装,则需要将上下文传递给模型。
module DocumentHTMLBoxes
extend ActiveSupport::Concern
included do
def icon_or_text(variable, context)
if context.action_name == 'send'
"<b>#{variable.name.capitalize}</b> #{variable.text}\n"
else
variable.format!
end
end
end
end
class Thing < ApplicationModel
include DocumentHTMLBoxes
end
恭喜,您刚刚创建了一些非常臭的代码。
但是,这是一个非常糟糕的主意,因为它只会给你的模型增加一个责任,这些模型已经接近Rails中的神级地位。不要将生成HTML(视图/帮助器责任!)添加到该列表中。
相反,您应该只创建一个简单的辅助方法:
module BoxesHelper
def icon_or_text(obj)
if context.action_name == 'send'
"<b>#{obj.name.capitalize}</b> #{obj.text}\n"
else
obj.format!
end
end
end
# @see https://ruby-doc.org/stdlib-2.1.0/libdoc/delegate/rdoc/Delegator.html
class Decorator < Delegator
attr_accessor :object
attr_accessor :context
def intialize(obj, cxt)
@object = obj
@context = cxt
super(obj) # pass obj to Delegator constructor, required
end
# Required by Delegator
def __getobj__
@object
end
def self.decorate(collection, context)
return collection.map { |record| self.new(record, context) }
end
end
module DocumentHTMLBoxes
extend ActiveSupport::Concern
included do
def icon_or_text(variable)
if context.action_name == 'send'
"<b>#{object.name.capitalize}</b> #{object.text}\n"
else
object.format!
end
end
end
end
class ThingDecorator < Decorator
include DocumentHTMLBoxes
end
要在控制器中装饰一堆记录,你可以这样做:
@things = ThingDecorator.decorate( Thing.all, self.view_context )
现在你可以在装饰模型上调用icon_or_text
:
<% @things.each do |t| %>
<% t.icon_or_text %>
<% end %>
答案 1 :(得分:2)
我建议重构代码以使其更清晰:
控制器级别调用就像
model_item.icon_or_text(variable, action_name)
模块
module DocumentHTMLBoxes
extend ActiveSupport::Concern
included do
def icon_or_text(variable, action_name)
if action_name == 'send'
"<b>#{variable.name.capitalize}</b> #{variable.text}\n"
else
variable.format!
end
end
end
end
答案 2 :(得分:0)
假设您将此问题包含在控制器中,那么在icon_or_text方法中,self就是控制器。您只需调用action_name,而无需在控制器前面添加前缀。
module DocumentHTMLBoxes
extend ActiveSupport::Concern
included do
def icon_or_text(variable)
if action_name == 'send'
"<b>#{variable.name.capitalize}</b> #{variable.text}\n"
else
variable.format!
end
end
end
end