首页 > 解决方案 > 如何以及在哪里定义在控制器中使用的方法?

问题描述

我希望在控制器中使用一种方法:

class Hash
  def sort_by_array a; Hash[sort_by{|k, _| a.index(k) || length}] end
end

但是将代码放入控制器后,我收到一个错误:class definition in method body

我尝试删除class Hash, 和 second end,并且也尝试过

class Hash
  def self.class.sort_by_array a; Hash[sort_by{|k, _| a.index(k) || length}] end
end

但我仍然无法让它停止出错

作为参考,这里是控制器:

class StaticPagesController < ApplicationController

  def main

  class Hash
    def self.class.sort_by_array a; Hash[sort_by{|k, _| a.index(k) || length}] end
  end

   @languages = Listing.group_by(&:language)
   @languages.sort_by_array(@languages)

  end

end

标签: ruby-on-rails

解决方案


当您在另一个类的方法中定义一个类时,就会发生该错误。即你可能正在做类似下面的事情:

class SomeClass
  def some_method
    class Hash
      def sort_by_array(a)
      end
    end
  end
end

假设你想Hash通过添加一个方法来扩展对象的功能sort_by_array,那么你可以像下面这样进行猴子修补:

解决方案(简单):

  • 您只能定义“实例”方法。如果您还想定义“类”方法,请参阅下面的“高级”解决方案。

库/扩展/hash.rb

module Extensions
  module Hash
    def sort_by_array(a)
      sort_by do |k, _|
        a.index(k) || length
      end
    end
  end
end

即假设您要扩展功能的另一个类:

lib/extensions/active_record/base.rb

module Extensions    
  module ActiveRecord
    module Base
      def say_hello_world
        puts 'Hello World!'
      end
    end
  end
end

config/initializers/extensions.rb

Hash.include Extensions::Hash
ActiveRecord::Base.include Extensions::ActiveRecord::Base

用法:

# rails console
some_array = [:a, :c, :b]
some_hash = { a: 1, b: 2, c: 3 }

some_hash.sort_by_array(some_array)
# => [[:a, 1], [:c, 3], [:b, 2]]


user = User.find(1)
user.say_hello_world
# => 'Hello World!'

解决方案(高级):

  • 现在允许定义“类”和“实例”方法:

库/扩展/hash.rb

module Extensions
  module Hash
    def self.included(base)
      base.extend ClassMethods
      base.include InstanceMethods
    end

    # define your Hash "class methods" here inside ClassMethods
    module ClassMethods
      # commented out because not yet fully working (check update later)
      # # feel free to remove this part (see P.S. for details)
      # def self.extended(base)
      #   instance_methods.each do |method_name|
      #     raise NameError, "#{method_name} method already defined!" if (base.singleton_methods - instance_methods).include? method_name
      #   end
      # end
    end

    # define your Hash "instance methods" here inside InstanceMethods
    module InstanceMethods
      # commented out because not yet fully working (check update later)
      # # feel free to remove this part (see P.S. for details)
      # def self.included(base)
      #   instance_methods.each do |method_name|
      #     raise NameError, "#{method_name} method already defined!" if (base.instance_methods - instance_methods).include? method_name
      #   end
      # end

      def sort_by_array(a)
        sort_by do |k, _|
          a.index(k) || length
        end
      end
    end
  end
end

即假设您要扩展功能的另一个类:

lib/extensions/active_record/base.rb

module Extensions    
  module ActiveRecord
    module Base
      def self.included(base)
        base.extend ClassMethods
        base.include InstanceMethods
      end

      module ClassMethods
        # commented out because not yet fully working (check update later)
        # # feel free to remove this part (see P.S. for details)
        # def self.extended(base)
        #   instance_methods.each do |method_name|
        #     raise NameError, "#{method_name} method already defined!" if (base.singleton_methods - instance_methods).include? method_name
        #   end
        # end

        def say_hello_mars
          puts 'Hello Mars!'
        end
      end

      module InstanceMethods
        # commented out because not yet fully working (check update later)
        # # feel free to remove this part (see P.S. for details)
        # def self.included(base)
        #   instance_methods.each do |method_name|
        #     raise NameError, "#{method_name} method already defined!" if (base.instance_methods - instance_methods).include? method_name
        #   end
        # end

        def say_hello_world
          puts 'Hello World!'
        end
      end
    end
  end
end

config/initializers/extensions.rb

Hash.include Extensions::Hash
ActiveRecord::Base.include Extensions::ActiveRecord::Base

用法:

# rails console
some_array = [:a, :c, :b]
some_hash = { a: 1, b: 2, c: 3 }

some_hash.sort_by_array(some_array)
# => [[:a, 1], [:c, 3], [:b, 2]]


user = User.find(1)
user.say_hello_world
# => 'Hello World!'
ActiveRecord::Base.say_hello_mars
# => 'Hello Mars!'

PS,如果方法已经定义,可以说你不需要引发错误,但这只是我个人防止“错误”的口味(例如,如果你使用的一些“宝石”也定义了相同的确切方法名称但有不同的功能,您无法控制)。随意删除它们。


推荐阅读