Как создать экземпляр класса из строки имени в Rails?

Как мы можем создать экземпляр класса из его строки имени в Ruby-on-Rails?

Например, у нас есть имя в базе данных в формате «ClassName» или «my_super_class_name».

Как мы можем создать объект из него?

<Сильный> Решение:

Я искал его сам, но не нашел, так что вот оно. API-интерфейсruby-on-rails

name = "ClassName"
instance = name.constantize.new  

Он может быть даже не отформатирован, мы можем использовать метод пользовательской строки .classify

name = "my_super_class"
instance = name.classify.constantize.new

Конечно, возможно, это не очень «Rails way», но это решает его цель.

61
nl ja de
Просто FYI, constantize - это удобный метод ActiveSupport, который выполняет Object.const_get , а Classify - метод ActiveSupport, который пытается превратить строку в стандартное форматирование класса. То, что вы делаете, идентично ответу Evginey, с некоторыми дополнительными проверками. Хотя константизация, вероятно, является лучшим решением (потому что это делает проверки на здравомыслие), это помогает понять используемые вами инструменты.
добавлено автор quandrum, источник
Спасибо за это, если честно, не проверил, что он делает в ручном режиме.
добавлено автор Vjatseslav Gedrovits, источник

4 ответы

klass = Object.const_get "ClassName"

о методах класса

class KlassExample
    def self.klass_method
        puts "Hello World from Class method"
    end
end
klass = Object.const_get "KlassExample"
klass.klass_method

irb(main):061:0> klass.klass_method
Hello World from Class method
65
добавлено
При этом вы не можете получить доступ к методам класса. Мое решение выше корректно работает с методами класса.
добавлено автор Vjatseslav Gedrovits, источник
Загрузка среды разработки (Rails 3.2.9) irb (main): 001: 0> name = "PartnerGateway" => "PartnerGateway" irb (main): 002: 0> klass = name.constantize.new => # irb (main): 003: 0> klass.name => nil
добавлено автор Vjatseslav Gedrovits, источник
irb (main): 005: 0> klass2 = Object.const_get name => PartnerGateway (id: integer, name: string, partner_id: integer, gateway: string, changed_by_id: integer, deleted_at: datetime, created_at: datetime, update_at: datetime) irb (main): 006: 0> klass2.name => «PartnerGateway» irb (main): 008: 0> klass2.id NoMethodError: undefined method id 'для # <Класс: 0xac3e4c0> `
добавлено автор Vjatseslav Gedrovits, источник
С помощью моего метода вы можете сделать оба способа. Msgstr "" ".
добавлено автор Vjatseslav Gedrovits, источник
Вы думаете, что ваше решение элегантно и правильно? Проверьте верхний комментарий.
добавлено автор Vjatseslav Gedrovits, источник
да, вы можете
добавлено автор Eugene Rourke, источник
да ... это ничего не доказывает, что вы, очевидно, не называете новыми, вы используете «Object.const_get» try klass2.new.name
добавлено автор Eugene Rourke, источник
Ну, так что это можно сделать с помощью klass2 = (Object.const_get name) .ново, как вы делаете с klass = name.constantize.new
добавлено автор Eugene Rourke, источник
что ваша проблема? почему вы так настаиваете на том, чтобы доказать свой путь как-то лучше, когда он, очевидно, делает то же самое?
добавлено автор Eugene Rourke, источник

Другие могут также искать альтернативу, которая не выдает ошибки, если не сможет найти класс. safe_constantize - это просто.

class MyClass
end

"my_class".classify.safe_constantize.new #  #
"omg_evil".classify.safe_constantize.new #  nil 
28
добавлено

Я удивлен, что никто не рассматривает безопасность и взлом в своих ответах. Игнорирование произвольной строки, которая, скорее всего, косвенно поступает с пользовательского ввода, вызывает проблемы и взлом. Мы все должны/должны быть whitelisting, если мы не уверены, что строка полностью контролируется и контролируется

def class_for(name)
  {
    "foo" => Foo,
    "bar" => Bar,
  }[name] || raise UnknownClass
end

class_for(name_wherever_this_came_from).create!(params_somehow)

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

3
добавлено

Вы можете просто преобразовать строку и инициализировать класс из нее:

klass_name = "Module::ClassName"
klass_name.constantize

Для инициализации нового объекта:

klass_name.constantize.new

Надеюсь, это окажется полезным. Благодаря!

2
добавлено
pro.ruby
pro.ruby
1 181 участник(ов)

Язык программирования Ruby Additional docs: https://rubyreferences.github.io/rubyref/ Invite: https://telegram.me/joinchat/Be4rsT2NuB3CyJaF26j1kA Кто хочет компилировать: @crystal_ru (его синтаксис основан на Ruby) Участник @proDOT

Ruby, Rails, Hanami | dry-rb
Ruby, Rails, Hanami | dry-rb
1 180 участник(ов)

https://telegram.me/rubyjob - Ruby Job По вопросам - @eugene_shved

Ruby School .us
Ruby School .us
1 045 участник(ов)

Чат-болталка для учеников руби-школы и не только. Правила: https://telegra.ph/Pravila-chata-Rubi-shkoly-03-13

Random Ruby Chat
Random Ruby Chat
589 участник(ов)

Правила публикации вакансий: https://t.me/codenamecrud/60865

Rubyata
Rubyata
333 участник(ов)

Коммюнити Ruby и Ruby On Rails Флуд не приветствуются. Вакансии можно публиковать только и ТОЛЬКО по пятницам с хештегом #вакансия.

Ruby Talks
Ruby Talks
236 участник(ов)

Национальная Флеймотека

RubyRush
RubyRush
189 участник(ов)

rubyrush.ru программирование для самых новичков

Rails Chat
Rails Chat
87 участник(ов)

You are welcome to discuss Ruby On Rails development process and other stuff