Как и где определить метод для использования в контроллере? - PullRequest
0 голосов
/ 22 февраля 2019

Я хочу использовать метод в контроллере:

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

Но после помещения кода в контроллер я получаю сообщение об ошибке: class definition in method body

Я попытался удалить class Hash, а второй 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

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Эта ошибка возникает, когда вы определяете класс внутри метода другого класса.то есть вы, вероятно, делали что-то вроде ниже:

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

Предполагая, что вы хотите расширить функциональность Hash объектов, добавив метод sort_by_array, тогда вы можете выполнить патч обезьяны, как показано ниже:

Решение (Простое):

  • Вы можете определять только методы «экземпляра».Если вы хотите определить также методы «класса», см. «Расширенное» решение ниже.

lib / extensions / 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!'

Решение (Advanced):

  • теперь разрешает как "класс", так иМетоды «instance», которые будут определены:

lib / extensions / 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, возможно, вам не нужно будет выдавать ошибку, если метод уже определен, но это мой личный вкус предотвратить"ошибки" (то есть, если, например, некоторые "драгоценные камни", которые вы использовали, также определилиодно и то же точное имя метода, но с другой функциональностью, которую вы не можете контролировать).Не стесняйтесь их удалять.

0 голосов
/ 22 февраля 2019

Поместите его в отдельный файл.Это расширило бы базовый класс Hash и позволило бы использовать его во всем приложении.

Самым простым было бы поместить код в config/initializers/hash.rb и перезапустить сервер.

Или,лучше, аналогично тому, как это делает Rails (например, https://github.com/rails/rails/tree/master/activesupport/lib/active_support/core_ext):

Поместите свой код здесь: lib/core_ext/hash/sort_by_array.rb

А затем либо добавьте этот путь в автозагрузку, либо запрашивайте его вручную, откудавы хотели бы использовать его, как это:

require "core_ext/hash/sort_by_array".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...