Tampilan dan pengontrol Rails saya dipenuhi redirect_to
,link_to
, dan form_for
metode panggilan. Kadang link_to
- kadang dan redirect_to
eksplisit di jalur yang mereka tautkan (misalnya link_to 'New Person', new_person_path
), tetapi berkali-kali jalur tersebut tersirat (misalnya link_to 'Show', person
).
Saya menambahkan beberapa tabel pewarisan tunggal (STI) ke model saya (katakanlah Employee < Person
), dan semua metode ini istirahat untuk turunan dari subclass (katakanlah Employee
); ketika rel dieksekusi link_to @person
, kesalahan dengan undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>
. Rails mencari rute yang ditentukan oleh nama kelas objek, yaitu karyawan. Rute karyawan ini tidak ditentukan, dan tidak ada pengontrol karyawan sehingga tindakannya juga tidak ditentukan.
Pertanyaan ini telah diajukan sebelumnya:
- Di StackOverflow , jawabannya adalah mengedit setiap instance dari link_to dll di seluruh basis kode Anda, dan nyatakan path secara eksplisit
- Di StackOverflow lagi, dua orang menyarankan menggunakan
routes.rb
untuk memetakan sumber daya subclass ke kelas induk (map.resources :employees, :controller => 'people'
). Jawaban teratas dalam pertanyaan SO yang sama menyarankan tipe-casting setiap instance objek dalam basis kode menggunakan.becomes
- Namun satu lagi di StackOverflow , jawaban teratas adalah cara di kamp Do Repeat Yourself, dan menyarankan untuk membuat duplikat perancah untuk setiap subclass.
- Ini dia pertanyaan yang sama lagi di SO, di mana jawaban teratas sepertinya salah (Rails magic Just Works!)
- Di tempat lain di web, saya menemukan posting blog ini mana F2Andy merekomendasikan pengeditan di jalur mana pun dalam kode.
- Pada posting blog Single Table Inheritance dan RESTful Routes at Logical Reality Design, direkomendasikan untuk memetakan sumber daya untuk subclass ke pengontrol superclass, seperti pada jawaban SO nomor 2 di atas.
- Alex Reisner memiliki posting Single Table Inheritance in Rails , di mana ia menganjurkan untuk tidak memetakan sumber daya dari kelas anak ke kelas induk di
routes.rb
, karena itu hanya menangkap kerusakan rute darilink_to
danredirect_to
, tetapi tidak dariform_for
. Jadi dia merekomendasikan sebagai gantinya menambahkan metode ke kelas induk untuk membuat subclass berbohong tentang kelas mereka. Kedengarannya bagus, tetapi metodenya memberi saya kesalahanundefined local variable or method `child' for #
.
Jadi jawaban yang tampaknya paling elegan dan memiliki paling konsensus (tapi itu tidak semua yang elegan, atau yang banyak konsensus), adalah menambah sumber daya untuk Anda routes.rb
. Kecuali ini tidak berhasil form_for
. Saya perlu kejelasan! Untuk menyaring pilihan di atas, opsi saya adalah
- memetakan sumber daya dari subclass ke controller dari superclass di
routes.rb
(dan harap saya tidak perlu memanggil form_for pada subclass mana pun) - Mengganti metode internal rel untuk membuat kelas berbohong satu sama lain
- Edit setiap instance dalam kode di mana path ke tindakan objek dipanggil secara implisit atau eksplisit, baik mengubah path atau ketik-casting objek.
Dengan semua jawaban yang saling bertentangan ini, saya perlu keputusan. Bagi saya sepertinya tidak ada jawaban yang baik. Apakah ini gagal dalam desain rel? Jika demikian, apakah itu bug yang mungkin diperbaiki? Atau jika tidak, maka saya berharap seseorang dapat meluruskan hal ini, memandu saya melalui pro dan kontra dari setiap opsi (atau menjelaskan mengapa itu bukan pilihan), dan mana yang merupakan jawaban yang tepat, dan mengapa. Atau ada jawaban yang tepat yang tidak saya temukan di web?
sumber
Jawaban:
Ini adalah solusi paling sederhana yang saya dapat buat dengan efek samping minimal.
Sekarang
url_for @person
akan dipetakancontact_path
sesuai yang diharapkan.Cara kerjanya: Pembantu URL mengandalkan
YourModel.model_name
untuk merefleksikan model dan menghasilkan (di antara banyak hal) kunci rute tunggal / jamak. Di siniPerson
pada dasarnya mengatakan aku sepertiContact
pria, tanyakan padanya .sumber
build_x
/create_x
). Di sisi lain, harga bermain sihir adalah Anda tidak pernah 100% yakin apa yang dapat berubah.Saya memiliki masalah yang sama. Setelah menggunakan IMS,
form_for
metode memposting ke url anak yang salah.Saya akhirnya menambahkan rute tambahan untuk kelas anak dan mengarahkan mereka ke pengontrol yang sama
Selain itu:
dalam hal ini struktur sebenarnya adalah sebuah bangunan (kelas anak)
Tampaknya bekerja untuk saya setelah melakukan pengiriman dengan
form_for
.sumber
Saya sarankan Anda melihat di: https://stackoverflow.com/a/605172/445908 , menggunakan metode ini akan memungkinkan Anda untuk menggunakan "form_for".
sumber
<%= form_for @child, :as => :child, url: @child.becomes(Parent)
<%= form_for @child.becomes(Parent)
Gunakan ketik di rute:
http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-2/
sumber
Mengikuti gagasan @Prathan Thananart tetapi berusaha untuk tidak menghancurkan apa pun. (Karena ada begitu banyak sihir yang terlibat)
Sekarang url_for @person akan memetakan ke contact_path seperti yang diharapkan.
sumber
Saya mengalami masalah dengan masalah ini juga dan datang dengan jawaban ini pada pertanyaan yang mirip dengan kita. Ini berhasil untuk saya.
Jawaban ditunjukkan di sini: Menggunakan jalur IMS dengan pengontrol yang sama
The
.becomes
Metode didefinisikan sebagai terutama digunakan untuk memecahkan masalah IMS seperti Andaform_for
satu..becomes
info di sini: http://apidock.com/rails/ActiveRecord/Base/becomesRespons yang sangat terlambat, tetapi ini adalah jawaban terbaik yang bisa saya temukan dan itu bekerja dengan baik untuk saya. Semoga ini bisa membantu seseorang. Bersulang!
sumber
Ok, saya punya banyak frustrasi di area Rails ini, dan telah sampai pada pendekatan berikut, mungkin ini akan membantu orang lain.
Pertama-tama perlu diketahui bahwa sejumlah solusi di atas dan di sekitar internet menyarankan penggunaan constantize pada parameter yang disediakan klien. Ini adalah vektor serangan DoS yang dikenal karena Ruby tidak membuang simbol pengumpulan, sehingga memungkinkan penyerang untuk membuat simbol sewenang-wenang dan menggunakan memori yang tersedia.
Saya telah menerapkan pendekatan di bawah ini yang mendukung instantiation model subclass, dan AMAN dari masalah contantize di atas. Ini sangat mirip dengan apa yang dilakukan rails 4, tetapi juga memungkinkan lebih dari satu level subclassing (tidak seperti Rails 4) dan bekerja di Rails 3.
Setelah mencoba berbagai pendekatan untuk 'pemuatan subclass dalam masalah devlopment' banyak mirip dengan apa yang disarankan di atas, saya menemukan satu-satunya hal yang bekerja dengan andal adalah dengan menggunakan 'memerlukan_dependensi' di kelas model saya. Ini memastikan bahwa pemuatan kelas berfungsi dengan baik dalam pengembangan dan tidak menyebabkan masalah dalam produksi. Dalam pengembangan, tanpa AR 'memerlukan_dependensi' tidak akan tahu tentang semua subclass, yang berdampak pada SQL yang dikeluarkan untuk pencocokan pada kolom tipe. Selain itu tanpa 'memerlukan_dependensi' Anda juga dapat berakhir dalam situasi dengan beberapa versi kelas model pada saat yang sama! (mis. ini bisa terjadi ketika Anda mengubah kelas dasar atau menengah, sub-kelas sepertinya tidak selalu dimuat ulang dan dibiarkan subclass dari kelas lama)
Saya juga tidak menimpa model_name seperti yang disarankan di atas karena saya menggunakan I18n dan memerlukan string yang berbeda untuk atribut subkelas yang berbeda, misalnya: tax_identifier menjadi 'ABN' untuk Organisasi, dan 'TFN' untuk Orang (di Australia).
Saya juga menggunakan pemetaan rute, seperti yang disarankan di atas, mengatur tipe:
Selain pemetaan rute, saya menggunakan InheritedResources dan SimpleForm dan saya menggunakan pembungkus formulir umum berikut untuk tindakan baru:
... dan untuk tindakan edit:
Dan untuk membuat ini bekerja, di basis saya ResourceContoller saya mengekspos resource_request_name InheritedResource sebagai metode pembantu untuk tampilan:
Jika Anda tidak menggunakan InheritedResources, gunakan sesuatu seperti yang berikut ini di 'ResourceController' Anda:
Selalu senang mendengar pengalaman dan peningkatan orang lain.
sumber
Baru-baru ini saya mendokumentasikan upaya saya untuk mendapatkan pola IMS stabil yang bekerja di aplikasi Rails 3.0. Inilah versi TL; DR:
Pendekatan ini mengatasi masalah yang Anda daftarkan dan juga sejumlah masalah lain yang dimiliki orang lain dengan pendekatan IMS.
sumber
Anda dapat mencoba ini, jika Anda tidak memiliki rute bersarang:
Atau Anda bisa pergi ke arah lain dan menggunakan sihir OOP seperti yang dijelaskan di sini: https://coderwall.com/p/yijmuq
Dengan cara kedua Anda bisa membuat pembantu serupa untuk semua model bersarang Anda.
sumber
Ini adalah cara bersih dan aman untuk membuatnya berfungsi dalam bentuk dan di seluruh aplikasi Anda yang kami gunakan.
Kemudian saya miliki dalam bentuk saya. Bagian yang ditambahkan untuk ini adalah sebagai:: distrik.
Semoga ini membantu.
sumber
Solusi terbersih yang saya temukan adalah menambahkan yang berikut ke kelas dasar:
Ini bekerja untuk semua subclass dan jauh lebih aman daripada menimpa seluruh objek nama model. Dengan hanya menargetkan kunci rute, kami menyelesaikan masalah perutean tanpa melanggar I18n atau mempertaruhkan potensi efek samping yang disebabkan oleh mengganti nama model seperti yang didefinisikan oleh Rails.
sumber
Jika saya mempertimbangkan warisan IMS seperti ini:
di 'app / models / a_model.rb' saya tambahkan:
Dan kemudian di kelas AModel:
Oleh karena itu saya bahkan dapat dengan mudah memilih model mana yang ingin saya gunakan yang default, dan ini bahkan tanpa menyentuh definisi sub-kelas. Sangat kering.
sumber
Cara ini berfungsi untuk saya ok (tentukan metode ini di kelas dasar):
sumber
Anda dapat membuat metode yang mengembalikan objek dummy Parent untuk tujuan routing
dan kemudian cukup panggil form_for @ employee.routing_object yang tanpa tipe akan mengembalikan objek kelas Person
sumber
Mengikuti @ prathan-thananart jawaban, dan untuk beberapa kelas IMS, Anda dapat menambahkan yang berikut ke model induk ->
Yang akan membuat setiap form dengan data Hubungi untuk mengirim params sebagai
params[:contact]
bukanparams[:contact_person]
,params[:contact_whatever]
.sumber
meretas, tetapi hanya satu lagi ke daftar solusi.
bekerja pada rel 2.x dan 3.x
sumber
Child.new
mengembalikanParent
kelas daripada subclass. Ini berarti bahwa Anda tidak dapat membuat subclass melalui penugasan massal melalui pengontrol (karenatype
merupakan atribut yang dilindungi secara default) kecuali Anda juga mengatur atribut type secara eksplisit.