Мои Рельсы мнение и контроллеры завалены redirect_to
, link_to
и form_for
вызовами методов. Иногда link_to
и redirect_to
явно в путях, которые они связывают (например,link_to 'New Person', new_person_path
), но много раз пути являются неявными (например link_to 'Show', person
).
Я добавляю некоторое наследование таблицы (STI) в мою модель (скажем Employee < Person
), и все эти методы ломаются для экземпляра подкласса (скажем Employee
); когда рельсы выполняются link_to @person
, это ошибки сundefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>
. Rails ищет маршрут, определенный именем класса объекта, который является сотрудником. Эти маршруты сотрудников не определены, и нет контроллера сотрудников, поэтому действия также не определены.
Этот вопрос был задан ранее:
- В StackOverflow ответ заключается в том, чтобы отредактировать каждый экземпляр link_to и т. Д. Во всей кодовой базе и явно указать путь
- На StackOverflow снова, два человека предлагают использовать
routes.rb
для сопоставления подкласса ресурсов на родительский класс (map.resources :employees, :controller => 'people'
). Верхний ответ в этом же вопросе SO предлагает приведение типов каждого объекта экземпляра в кодовой базе с использованием.becomes
- Еще один в StackOverflow , лучший ответ - путь в лагере Do Repeat Yourself, и предлагает создать дублированные леса для каждого подкласса.
- Вот тот же вопрос снова в SO, где верхний ответ кажется просто неправильным (Rails magic Just Works!)
- В другом месте в Интернете я нашел этот пост где F2Andy рекомендует редактировать путь повсюду в коде.
- В сообщении блога « Одиночное наследование таблиц» и «RESTful-маршруты» в проекте « Логическая реальность» рекомендуется сопоставить ресурсы для подкласса с контроллером суперкласса, как в ответе SO 2 выше.
- У Алекса Рейснера есть пост- наследование таблиц в Rails , в котором он выступает против сопоставления ресурсов дочерних классов с родительским классом в
routes.rb
, поскольку он только отлавливает разрывы маршрутизации отlink_to
иredirect_to
, но не отform_for
. Поэтому он рекомендует вместо этого добавить метод в родительский класс, чтобы подклассы лгали об их классе. Звучит хорошо, но его метод дал мне ошибкуundefined local variable or method `child' for #
.
Таким образом, ответ , который кажется наиболее элегантно и имеет наибольший консенсус (но это еще не все , что элегантным, ни что много консенсуса), является добавление ресурсов к вашему routes.rb
. За исключением того, что это не работает для form_for
. Мне нужна ясность! Чтобы выбрать варианты выше, мои варианты
- сопоставить ресурсы подкласса с контроллером суперкласса в
routes.rb
(и надеюсь, мне не нужно вызывать form_for для любых подклассов) - Переопределить рельсы внутренними методами, чтобы классы лгали друг другу
- Отредактируйте каждый экземпляр в коде, где путь к действию объекта вызывается неявно или явно, либо изменяя путь, либо приводя тип к объекту.
Со всеми этими противоречивыми ответами мне нужно решение. Мне кажется, что нет хорошего ответа. Это неудачный дизайн рельсов? Если так, то это ошибка, которая может быть исправлена? Или, если нет, то я надеюсь, что кто-то может объяснить мне это, показать мне плюсы и минусы каждого варианта (или объяснить, почему это не вариант), какой из них правильный и почему. Или есть правильный ответ, который я не нахожу в Интернете?
источник
Ответы:
Это самое простое решение, которое мне удалось найти с минимальным побочным эффектом.
Теперь
url_for @person
сопоставим сcontact_path
ожидаемым.Как это работает: URL-помощники полагаются на то,
YourModel.model_name
что они размышляют над моделью и генерируют (среди многих вещей) одиночные / множественные ключи маршрута. ВотPerson
в основном говорят, что я просто какContact
чувак, спросите его .источник
build_x
/create_x
). С другой стороны, цена игры с магией в том, что вы никогда не уверены на 100%, что может измениться.У меня такая же проблема. После использования STI
form_for
метод отправлялся по неправильному URL-адресу ребенка.В итоге я добавил дополнительные маршруты для дочерних классов и указал их на те же контроллеры
Дополнительно:
в этом случае структура фактически является зданием (дочерним классом)
Кажется, это работает для меня после выполнения с
form_for
.источник
Я предлагаю вам взглянуть на: https://stackoverflow.com/a/605172/445908 , использование этого метода позволит вам использовать "form_for".
источник
<%= form_for @child, :as => :child, url: @child.becomes(Parent)
<%= form_for @child.becomes(Parent)
Используйте тип в маршрутах:
http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-2/
источник
Следуя идее @Prathan Thananart, но стараясь не разрушать ничего. (так как в этом задействовано столько магии)
Теперь url_for @person будет отображаться в contact_path, как и ожидалось.
источник
У меня тоже были проблемы с этой проблемой, и я получил ответ на вопрос, похожий на наш. Это сработало для меня.
Ответ показан здесь: Использование STI-пути с тем же контроллером
.becomes
Метод определяется как используется в основном для решения проблем ИППП , как вашform_for
друг..becomes
информация здесь: http://apidock.com/rails/ActiveRecord/Base/becomesСупер поздний ответ, но это лучший ответ, который я мог найти, и он работал хорошо для меня. Надеюсь, это кому-нибудь поможет. Ура!
источник
Хорошо, у меня было множество разочарований в этой области Rails, и я пришел к следующему подходу, возможно, это поможет другим.
Во-первых, имейте в виду, что ряд решений выше и вокруг сети предлагают использовать constantize для предоставленных клиентом параметров. Это известный вектор DoS-атак, поскольку Ruby не собирает символы мусора, что позволяет злоумышленнику создавать произвольные символы и использовать доступную память.
Ниже реализован подход, который поддерживает создание экземпляров подклассов модели и является БЕЗОПАСНЫМ из вышеописанной проблемы. Это очень похоже на то, что делает rails 4, но также позволяет использовать более одного уровня подклассов (в отличие от Rails 4) и работает в Rails 3.
Попробовав различные подходы к «загрузке подкласса в проблеме devlopment», многие из которых были похожи на предложенные выше, я обнаружил, что единственное, что надежно работает, - это использование require_dependency в моих модельных классах. Это гарантирует, что загрузка классов работает должным образом при разработке и не вызывает проблем в производстве. В процессе разработки без 'require_dependency' AR не будет знать обо всех подклассах, что влияет на SQL, выдаваемый для сопоставления в столбце типа. Кроме того, без 'require_dependency' вы также можете оказаться в ситуации с несколькими версиями классов модели одновременно! (например, это может произойти, когда вы изменяете базовый или промежуточный класс, кажется, что подклассы не всегда перезагружаются и остаются подклассами из старого класса)
Я также не перезаписываю model_name, как предложено выше, потому что я использую I18n и мне нужны разные строки для атрибутов разных подклассов, например: tax_identifier становится 'ABN' для организации и 'TFN' для персоны (в Австралии).
Я также использую отображение маршрута, как предложено выше, устанавливая тип:
В дополнение к сопоставлению маршрутов я использую InheritedResources и SimpleForm и использую следующую универсальную оболочку формы для новых действий:
... и для редактирования действий:
И чтобы это работало, в моем базовом ResourceContoller я предоставляю имя_ресурса_ресурса InheritedResource как вспомогательный метод для представления:
Если вы не используете InheritedResources, используйте в ResourceController что-то вроде следующего:
Всегда рады услышать от других опыт и улучшения.
источник
Недавно я задокументировал свои попытки заставить стабильный шаблон STI работать в приложении Rails 3.0. Вот версия TL; DR:
Этот подход позволяет обойти проблемы, которые вы перечислите, а также ряд других проблем, которые были у других с подходами к ИППП.
источник
Вы можете попробовать это, если у вас нет вложенных маршрутов:
Или вы можете пойти другим путем и использовать некоторую ООП-магию, как описано здесь: https://coderwall.com/p/yijmuq
Вторым способом вы можете сделать аналогичные помощники для всех ваших вложенных моделей.
источник
Вот безопасный, чистый способ заставить его работать в формах и во всем приложении, которое мы используем.
Тогда я в своей форме. Добавленная часть для этого является как:: район.
Надеюсь это поможет.
источник
Самое чистое решение, которое я нашел, это добавить следующее в базовый класс:
Он работает для всех подклассов и намного безопаснее, чем переопределение всего объекта имени модели. Ориентируясь только на ключи маршрута, мы решаем проблемы маршрутизации, не нарушая I18n и не рискуя какими-либо потенциальными побочными эффектами, вызванными переопределением имени модели, как определено Rails.
источник
Если я рассматриваю наследование от ИППП следующим образом:
в 'app / models / a_model.rb' я добавляю:
А затем в классе AModel:
Поэтому я даже могу легко выбрать, какую модель я хочу использовать по умолчанию, и даже не касаясь определения подкласса. Очень сухой.
источник
Этот способ работает для меня хорошо (определите этот метод в базовом классе):
источник
Вы можете создать метод, который возвращает фиктивный родительский объект для маршрутизации
а затем просто вызовите form_for @ employee.routing_object, который без типа вернет объект класса Person
источник
После ответа @ prathan-thananart и для нескольких классов STI вы можете добавить следующее в родительскую модель ->
Это сделает каждую форму с данными Контакта для отправки Params , как
params[:contact]
вместо того , чтобыparams[:contact_person]
,params[:contact_whatever]
.источник
хак, но просто еще один список решений.
работает на рельсах 2.x и 3.x
источник
Child.new
он возвращаетParent
класс, а не подкласс. Это означает, что вы не можете создавать подклассы с помощью массового назначения через контроллер (посколькуtype
по умолчанию это защищенный атрибут), если вы также не установили атрибут type явно.