Rails 5:模块中的控制器动作

时间:2017-09-21 08:43:53

标签: ruby-on-rails model-view-controller ruby-on-rails-5

我意识到这是针对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

3 个答案:

答案 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

decorator

# @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)

我建议重构代码以使其更清晰:

  1. 控制器级别调用就像

    model_item.icon_or_text(variable, action_name)
    
  2. 模块

    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