在另一个类中调用方法?

时间:2018-01-03 08:19:47

标签: ruby-on-rails ruby

我在不同的命名空间(a和b)中有两个控制器,如下所示:

class A::TechnologiesController < ApplicationController
  def index
    render json: Technology.all
  end
end

class B::TechnologiesController < ApplicationController
  def index
    render json: Technology.all
  end
end

这两个动作执行相同的逻辑,我相信这是一个重复。我想消除重复,所以我如何借用下面的命名空间中的代码?

class B::TechnologiesController < ApplicationController
  def index
    A::TechnologiesController.method(:index).call self
  end
end

4 个答案:

答案 0 :(得分:3)

回答评论中陈述的隐含问题:如果且仅对象调用bind is_a?()实例,则可以使用UnboundMethod#bind 借用该方法方法所属的类:

def index
  A::TechnologiesController.instance_method(:index).bind(self).()
end

但这既不惯用也不可读。一个人应该使用mixin:

module Mixins::TechnologiesController
  def index
    render json: Technology.all
  end
end

class A::TechnologiesController < ApplicationController
  include Mixins::TechnologiesController
end
class B::TechnologiesController < ApplicationController
  include Mixins::TechnologiesController
end

或共同的祖先:

class Base::TechnologiesController < ApplicationController
  def index
    render json: Technology.all
  end
end
class A::TechnologiesController < Base::TechnologiesController; end
class B::TechnologiesController < Base::TechnologiesController; end

Bonus track:在Rails中,可以使用Module#delegate monkeypatch。

Bonus track#2:procs的实现存储为常量:

class A::TechnologiesController < ApplicationController
  INDEX = -> { render json: Technology.all }
  def index
    INDEX.()
  end
end

class B::TechnologiesController < ApplicationController
  def index
    A::INDEX.()
  end
end

答案 1 :(得分:1)

这是mixin的一个很好的例子 有了这个,您可以干掉代码,而不必调用另一个控制器的方法。

这是模块:

module CommonInterface
  def render_technology
    render :json, Technology.all
  end
end

这将是你的控制者

class B::TechnologiesController < ApplicationController
  include CommonInterface
  def index
    render_technology
  end
end

答案 2 :(得分:0)

如果你想干嘛,祖先和mixin的答案真的很好,但在我看来你并不一定要这么做。 render json:位属于控制器操作。您希望您的操作在两个控制器中呈现内容。

查询可能会随着时间的推移以同样的方式发生变化我猜Technology.all,所以你可以在某处抽象,但同样,等待并查看是否是这种情况可能是个好主意。

如果您使用mixins或基类,您将耦合两个控制器,这可能没问题。但同样,你可能只想稍后做出这个决定。

答案 3 :(得分:0)

您可以通过在ApplicationController中创建一个super方法来解决上述问题 并且您需要在每个控制器中添加一个方法以将值传递给super方法,您不仅可以将其用于技术模型,还可以将其用于任何其他模型。

样本示例

在应用程序控制器中

    class StudentsController < ApplicationController

      def index
        super
      end

      def model
        Student
      end
    end




    class JobsController < ApplicationController
      def index
        super
      end
      def model
        Job
      end
    end

在每个控制器中,我们可以像这样调用上面的方法

    <% @collection.all.each do |student| %>
      <tr>
        <td><%= student.Name %></td>
        <td><%= student.Email %></td>
      </tr>
    <% end %>

您将在@collection中收集的数据,可以在视图中使用,例如

对于app / views / students / index.html.erb

    <% @collection.all.each do |job| %>
      <tr>
        <td><%= job.id %></td>
        <td><%= job.exp %></td>
      </tr>
    <% end %>

对于app / views / jobs / index.html.erb

RewriteRule ^page-url/(*)?$ [R=404,L]