Как программно найти имя пространства имен / модуля в Ruby on Rails?

Как найти имя пространства имен или модуля Foo в фильтре ниже?

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = ???
  end
end


class Foo::BarController < ApplicationController
  before_filter :get_module_name
end
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
61
0
49 565
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Это должно сделать это:

  def get_module_name
    @module_name = self.class.to_s.split("::").first
  end

или вы также можете использовать self.class.name.demodulize для этой цели.

TiSer 24.07.2012 14:15

нет, вы не можете, на самом деле demodulize возвращает имя класса без пространств имен

Fivell 12.12.2012 17:39

Как отметил Джейсон Харрельсон, при этом не учитываются несколько родительских модулей.

roychri 26.07.2013 00:05

Я не думаю, что есть способ очиститель, и я видел это где-то еще

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end

Это сработало бы, если бы у контроллера было имя модуля, но вернуло бы имя контроллера, если бы его не было.

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end

Однако, если мы немного изменим это на:

class ApplicatioNController < ActionController::Base
  def get_module_name
    my_class_name = self.class.name
    if my_class_name.index("::").nil? then
      @module_name = nil
    else
      @module_name = my_class_name.split("::").first
    end
  end
end

Вы можете определить, есть ли у класса имя модуля или нет, и вернуть что-то еще, кроме имени класса, которое вы можете проверить.

Я знаю, что это старый поток, но я только что столкнулся с необходимостью иметь отдельную навигацию в зависимости от пространства имен контроллера. Решение, которое я придумал, заключалось в следующем в моем макете приложения:

<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>

Это выглядит немного сложным, но в основном делает следующее - он принимает имя класса контроллера, которое может быть, например, «People» для контроллера без пространства имен и «Admin :: Users» для контроллера с пространством имен. Использование строкового метода [] с регулярным выражением, которое возвращает что-либо до двух двоеточий или nil, если ничего нет. Затем он меняет его на нижний регистр («попытка» присутствует в случае отсутствия пространства имен и возвращается nil). Это оставляет нам либо пространство имен, либо ноль. Затем он просто отображает партиал с пространством имен или без него, например без пространства имен:

app/views/_nav.html.erb

или в пространстве имен администратора:

app/views/admin/_nav.html.erb

Конечно, эти частичные данные должны существовать для каждого пространства имен, иначе произойдет ошибка. Теперь навигация для каждого пространства имен будет отображаться для каждого контроллера без необходимости изменять какой-либо контроллер или представление.

Ответ принят как подходящий

Ни одно из этих решений не рассматривает константу с несколькими родительскими модулями. Например:

A::B::C

Начиная с Rails 3.2.x вы можете просто:

"A::B::C".deconstantize #=> "A::B"

Начиная с Rails 3.1.x вы можете:

constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )

Это потому, что #demodulize является противоположностью #deconstantize:

"A::B::C".demodulize #=> "C"

Если вам действительно нужно сделать это вручную, попробуйте следующее:

constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]

Этот вопрос был написан до Rails 3, и модули на самом деле не поддерживались. Обновлен принятый ответ, чтобы отразить более актуальные версии!

Steropes 06.09.2013 18:42

демодуляция была ключевым ответом

Donato 03.03.2015 05:40

Я рекомендую gsub вместо split. Это более эффективно, чем split, учитывая, что вам не нужно другое имя модуля.

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.to_s.gsub(/::.*/, '')
  end
end

my_class.name.underscore.split('/').slice(0..-2)

или же

my_class.name.split('::').slice(0..-2)

В простом случае вы можете использовать:

self.class.parent

Это доступно только в последних версиях Rubies? Не могу поверить, что существует так много ответов о «темной магии», и никто не ссылался на этот метод до 2015 года.

Cyril Duchon-Doris 24.01.2018 14:57

Не могу найти в документе ... Я даже не могу воспроизвести :) Я предпочитаю этот ответ сейчас: stackoverflow.com/questions/14778816/…: class C; end; C.new.class.superclass -> Объект

Hettomei 01.07.2019 13:14

Думаю, мое решение сработало из-за рельсов: rubydoc.info/docs/rails/4.1.7/Module#parent-instance_method

Hettomei 01.07.2019 13:16

Со многими подмодулями:

module ApplicationHelper
  def namespace
    controller.class.name.gsub(/(::)?\w+Controller$/, '')
  end
end

Пример: Foo::Bar::BazController => Foo::Bar

Никто не упомянул использование rpartition?

const_name = 'A::B::C'
namespace, _sep, module_name = const_name.rpartition('::')
# or if you just need the namespace
namespace = const_name.rpartition('::').first

Для Rails 6.1

self.class.module_parent


Ответ Hettomei отлично работает до Rails 6.0

DEPRECATION WARNING: Module#parent has been renamed to module_parent. parent is deprecated and will be removed in Rails 6.1.

module_parent существует с Rails 6.0

Manuel Meurer 15.10.2020 15:19

Другие вопросы по теме