แนวทางปฏิบัติที่ดีที่สุดในการจัดการเส้นทางสำหรับคลาสย่อย STI ในทางรถไฟ


175

มุมมองทางรถไฟของฉันและตัวควบคุมจะเกลื่อนไปด้วย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 กำลังค้นหาเส้นทางที่กำหนดโดยชื่อคลาสของวัตถุซึ่งเป็นพนักงาน เส้นทางของพนักงานเหล่านี้ไม่ได้ถูกกำหนดไว้และไม่มีตัวควบคุมพนักงานดังนั้นการกระทำที่ไม่ได้กำหนดไว้

คำถามนี้ถูกถามมาก่อน:

  1. ที่StackOverflowคำตอบคือการแก้ไขทุก ๆ อินสแตนซ์ของ link_to ฯลฯ ในโค๊ดฐานทั้งหมดของคุณและระบุพา ธ อย่างชัดเจน
  2. ในStackOverflowอีกสองคนแนะนำให้ใช้routes.rbในการแมปทรัพยากรคลาสย่อยกับผู้ปกครองระดับ ( map.resources :employees, :controller => 'people') คำตอบที่ดีที่สุดในคำถาม SO เดียวกันนั้นแสดงให้เห็นถึงการหล่อแบบวัตถุทุกอินสแตนซ์ใน codebase ใช้.becomes
  3. อีกคำหนึ่งที่StackOverflowคำตอบที่ดีที่สุดคือวิธีในค่าย Do Repeat Yourself และแนะนำให้สร้าง scaffolding ซ้ำสำหรับทุกคลาสย่อย
  4. นี่คือคำถามเดียวกันอีกครั้งที่ SO ซึ่งคำตอบยอดนิยมดูเหมือนจะผิด (Rails magic Just Works!)
  5. ที่อื่นบนเว็บฉันพบโพสต์บล็อกนี้ที่ F2Andy แนะนำให้แก้ไขในเส้นทางทุกที่ในรหัส
  6. ในบล็อกโพสต์Single Table Inheritance และ RESTful Routesที่ Logical Reality Design ขอแนะนำให้แมปทรัพยากรสำหรับคลาสย่อยกับตัวควบคุม superclass ดังเช่นในคำตอบข้อที่ 2 ข้างต้น
  7. อเล็กซ์ Reisner มีการโพสต์เดี่ยวตารางมรดกในรางที่เขาสนับสนุนการต่อต้านการทำแผนที่ทรัพยากรของการเรียนเด็กกับผู้ปกครองชั้นในroutes.rbตั้งแต่ที่จับเฉพาะเส้นทางจากเหวอะหวะlink_toและแต่ไม่ได้มาจากredirect_to form_forดังนั้นเขาจึงแนะนำให้เพิ่มวิธีการในคลาสผู้ปกครองเพื่อให้คลาสย่อยนั้นเกี่ยวกับคลาสของพวกเขา เสียงดี undefined local variable or method `child' for #แต่วิธีการของเขาให้ฉันข้อผิดพลาด

ดังนั้นคำตอบที่ดูเหมือนว่าสง่างามมากที่สุดและมีความเห็นมากที่สุด ( แต่ก็ไม่ทั้งหมดที่สง่างามหรือว่าฉันทามติมาก) routes.rbคือการเพิ่มทรัพยากรที่จะของคุณ form_forยกเว้นนี้ไม่ได้ทำงานให้กับ ฉันต้องการความชัดเจน! เพื่อกลั่นตัวเลือกข้างต้นตัวเลือกของฉันคือ

  1. แมปทรัพยากรของคลาสย่อยกับตัวควบคุมของซูเปอร์คลาสในroutes.rb(และหวังว่าฉันไม่จำเป็นต้องเรียก form_for บนคลาสย่อยใด ๆ )
  2. แทนที่วิธีการภายในรางเพื่อให้ชั้นเรียนอยู่ซึ่งกันและกัน
  3. แก้ไขทุกอินสแตนซ์ในรหัสที่มีการเรียกใช้พา ธ ไปยังการกระทำของวัตถุโดยปริยายหรืออย่างชัดเจนไม่ว่าจะเป็นการเปลี่ยนเส้นทางหรือการพิมพ์วัตถุ

ด้วยคำตอบที่ขัดแย้งกันเหล่านี้ฉันต้องการคำวินิจฉัย ดูเหมือนว่าฉันจะไม่มีคำตอบที่ดี นี่เป็นความล้มเหลวในการออกแบบรางหรือไม่? ถ้าเป็นเช่นนั้นเป็นข้อผิดพลาดที่อาจได้รับการแก้ไขหรือไม่ หรือถ้าไม่ฉันก็หวังว่าจะมีใครบางคนสามารถกำหนดฉันให้ตรงกับสิ่งนี้เดินผ่านฉันผ่านข้อดีและข้อเสียของแต่ละตัวเลือก (หรืออธิบายว่าทำไมจึงไม่ใช่ตัวเลือก) และเป็นคำตอบที่ถูกต้อง หรือมีคำตอบที่ถูกที่ฉันไม่พบในเว็บ?


1
มีการพิมพ์ผิดในรหัสของ Alex Reisner ซึ่งเขาได้รับการแก้ไขหลังจากที่ฉันแสดงความคิดเห็นในบล็อกของเขา ดังนั้นหวังว่าตอนนี้ทางออกของ Alex จะเป็นไปได้ คำถามของฉันยังคงตั้งอยู่: ซึ่งเป็นทางออกที่เหมาะสม?
ziggurism

1
แม้ว่าจะมีอายุประมาณสามปี แต่ฉันก็พบโพสต์บล็อกนี้ที่rookieonrails.blogspot.com/2008/01/…และบทสนทนาที่เชื่อมโยงจากรายชื่อผู้รับจดหมายของรางรถไฟ ผู้เผชิญเหตุคนหนึ่งอธิบายความแตกต่างระหว่างผู้ช่วย polymorphic และผู้ช่วยที่ตั้งชื่อ
ziggurism

2
ตัวเลือกที่คุณไม่มีในรายการคือการแก้ไข Rails เพื่อให้ link_to, form_for และสถานที่ที่ถูกใจอยู่ด้วยการสืบทอดตารางเดี่ยว นั่นอาจเป็นงานที่ยาก แต่ก็เป็นสิ่งที่ฉันอยากเห็นคงที่
M. Scott Ford

คำตอบ:


140

นี่เป็นทางออกที่ง่ายที่สุดที่ฉันสามารถทำได้ด้วยผลข้างเคียงน้อยที่สุด

class Person < Contact
  def self.model_name
    Contact.model_name
  end
end

ตอนนี้url_for @personจะแมปcontact_pathตามที่คาดไว้

มันทำงานอย่างไร:ผู้ช่วย URL พึ่งพาYourModel.model_nameการสะท้อนให้เห็นถึงตัวแบบและสร้าง (ในหลาย ๆ สิ่ง) คีย์เส้นทางแบบเอกพจน์ / พหูพจน์ นี่Personเป็นพื้นบอกฉันเช่นเดียวกับContactเพื่อนขอให้เขา


4
ฉันกำลังคิดที่จะทำสิ่งเดียวกัน แต่ก็กังวลว่า #model_name อาจใช้ที่อื่นใน Rails และการเปลี่ยนแปลงนี้อาจรบกวนการทำงานปกติ ความคิดใด ๆ
nkassis

3
ฉันเห็นด้วยกับคนแปลกหน้าโดยสิ้นเชิง @nkassis นี่เป็นแฮ็คที่ยอดเยี่ยม แต่คุณจะรู้ได้อย่างไรว่าคุณไม่ได้กักขังตัวเองของทางรถไฟ
tsherif

6
รายละเอียด นอกจากนี้เราใช้รหัสนี้ในการผลิตและฉันสามารถยืนยันได้ว่ามันไม่เลอะ: 1) ความสัมพันธ์ระหว่างโมเดล 2) การสร้างอินสแตนซ์โมเดล STI (ผ่านbuild_x/ create_x) ในทางตรงกันข้ามราคาของการเล่นด้วยเวทมนตร์คือคุณไม่แน่ใจ 100% ว่าสิ่งที่อาจเปลี่ยนแปลง
Prathan Thananart

10
สิ่งนี้จะทำให้ i18n แตกต่างกันไปถ้าคุณพยายามที่จะมีชื่อบุคคลที่แตกต่างกันสำหรับแอตทริบิวต์ขึ้นอยู่กับคลาส
Rufo Sanchez

4
แทนที่จะเอาชนะอย่างนี้คุณสามารถแทนที่บิตที่คุณต้องการ ดูgist.github.com/sj26/5843855
sj26

47

ผมมีปัญหาเหมือนกัน. หลังจากใช้ STI form_forวิธีการโพสต์ไปยัง URL ของเด็กที่ไม่ถูกต้อง

NoMethodError (undefined method `building_url' for

ฉันสิ้นสุดการเพิ่มเส้นทางพิเศษสำหรับคลาสเด็กและชี้ไปที่ตัวควบคุมเดียวกัน

 resources :structures
 resources :buildings, :controller => 'structures'
 resources :bridges, :controller => 'structures'

นอกจากนี้:

<% form_for(@structure, :as => :structure) do |f| %>

ในกรณีนี้โครงสร้างจริง ๆ แล้วเป็นสิ่งปลูกสร้าง (คลาสเด็ก)

form_forมันดูเหมือนว่าจะทำงานสำหรับผมหลังจากทำส่งด้วย


2
ใช้งานได้ แต่เพิ่มเส้นทางที่ไม่จำเป็นจำนวนมากในเส้นทางของเรา ไม่มีวิธีการทำเช่นนี้ในลักษณะที่ล่วงล้ำน้อยกว่า
Anders Kindberg

1
คุณสามารถตั้งค่าเส้นทางโดยใช้โปรแกรมในไฟล์ PATH.rb ของคุณดังนั้นคุณสามารถทำการเขียนโปรแกรมเมตาเล็กน้อยเพื่อตั้งค่าเส้นทางเด็ก อย่างไรก็ตามในสภาพแวดล้อมที่คลาสไม่ได้ถูกแคช (เช่นการพัฒนา) คุณจะต้องโหลดคลาสล่วงหน้าก่อน ดังนั้นไม่ทางใดก็ทางหนึ่งคุณต้องระบุคลาสย่อยที่อื่น ดูgist.github.com/1713398เช่น
Chris Bloom

ในกรณีของฉันการเปิดเผยชื่อออบเจ็กต์ (พา ธ ) ไปยังผู้ใช้นั้นไม่เป็นที่ต้องการ (และทำให้ผู้ใช้สับสน)
laffuste

33

ฉันขอแนะนำให้คุณดูที่: https://stackoverflow.com/a/605172/445908 การใช้วิธีนี้จะช่วยให้คุณใช้ "form_for"

ActiveRecord::Base#becomes

2
ฉันต้องตั้งค่า url อย่างชัดเจนเพื่อให้สามารถเรนเดอร์จากและบันทึกอย่างถูกต้อง <%= form_for @child, :as => :child, url: @child.becomes(Parent)
lulalala

4
@lulalala ลอง<%= form_for @child.becomes(Parent)
Richard Jones

18

ใช้ประเภทในเส้นทาง:

resources :employee, controller: 'person', type: 'Employee' 

http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-2/


เปลี่ยนโดเมนแล้วบทความที่กล่าวถึงมีให้บริการแล้วที่นี่: samurails.com/tutorial/…
T_Dnzt

ลิงก์ในโพสต์และความคิดเห็นตายแล้ว
sasquatch

14

ติดตามแนวคิดของ @Prathan Thananart แต่พยายามไม่ทำลายอะไรเลย (เนื่องจากมีเวทมนตร์จำนวนมากที่เกี่ยวข้อง)

class Person < Contact
  model_name.class_eval do
    def route_key
     "contacts"
    end
    def singular_route_key
      superclass.model_name.singular_route_key
    end
  end
end

ตอนนี้ url_ สำหรับ @person จะแมปไปยัง contact_path ตามที่คาดไว้


14

ฉันมีปัญหากับปัญหานี้ด้วยและมาจากคำตอบของคำถามที่คล้ายกับของเรา มันใช้งานได้สำหรับฉัน

form_for @list.becomes(List)

คำตอบที่แสดงที่นี่: การใช้เส้นทาง STI ด้วยคอนโทรลเลอร์เดียวกัน

.becomesวิธีถูกกำหนดให้เป็นส่วนใหญ่ที่ใช้ในการแก้ปัญหาเช่น STI ของคุณform_forหนึ่ง

.becomesข้อมูลที่นี่: http://apidock.com/rails/ActiveRecord/Base/becomes

การตอบกลับช้าสุด ๆ แต่นี่เป็นคำตอบที่ดีที่สุดที่ฉันสามารถหาได้และมันก็ใช้ได้ดีสำหรับฉัน หวังว่านี่จะช่วยได้บ้าง ไชโย!


5

ตกลงฉันมีความหงุดหงิดมากมายในพื้นที่ของ Rails และได้มาถึงวิธีการต่อไปนี้ซึ่งอาจช่วยผู้อื่นได้

ก่อนอื่นให้ระวังว่าจำนวนของโซลูชั่นด้านบนและรอบ ๆ เน็ตแนะนำให้ใช้ค่าคงที่กับพารามิเตอร์ที่ลูกค้าให้ไว้ นี่เป็นเวคเตอร์การโจมตี DoS ที่รู้จักกันเนื่องจาก Ruby ไม่ได้ทิ้งสัญลักษณ์การรวบรวมดังนั้นผู้โจมตีสามารถสร้างสัญลักษณ์โดยพลการและใช้หน่วยความจำที่มีอยู่

ฉันได้ใช้วิธีการด้านล่างซึ่งรองรับอินสแตนซ์ของคลาสย่อยของโมเดลและปลอดภัยจากปัญหาด้านบน มันคล้ายกับสิ่งที่ราง 4 ทำ แต่ยังยอมให้ subclassing มากกว่าหนึ่งระดับ (ไม่เหมือนกับ Rails 4) และทำงานใน Rails 3

# initializers/acts_as_castable.rb
module ActsAsCastable
  extend ActiveSupport::Concern

  module ClassMethods

    def new_with_cast(*args, &block)
      if (attrs = args.first).is_a?(Hash)
        if klass = descendant_class_from_attrs(attrs)
          return klass.new(*args, &block)
        end
      end
      new_without_cast(*args, &block)
    end

    def descendant_class_from_attrs(attrs)
      subclass_name = attrs.with_indifferent_access[inheritance_column]
      return nil if subclass_name.blank? || subclass_name == self.name
      unless subclass = descendants.detect { |sub| sub.name == subclass_name }
        raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}")
      end
      subclass
    end

    def acts_as_castable
      class << self
        alias_method_chain :new, :cast
      end
    end
  end
end

ActiveRecord::Base.send(:include, ActsAsCastable)

หลังจากลองวิธีการต่าง ๆ สำหรับ 'การโหลด sublclass ในประเด็นการพัฒนาที่ไม่ดี' หลายอย่างคล้ายกับที่แนะนำไว้ข้างต้นฉันพบสิ่งเดียวที่ทำงานได้อย่างน่าเชื่อถือคือใช้ 'require_dependency' ในชั้นเรียนโมเดลของฉัน สิ่งนี้ทำให้มั่นใจได้ว่าการโหลดคลาสทำงานอย่างถูกต้องในการพัฒนาและไม่ทำให้เกิดปัญหาในการผลิต ในการพัฒนา AR ที่ไม่มี 'require_dependency' จะไม่ทราบเกี่ยวกับคลาสย่อยทั้งหมดซึ่งส่งผลกระทบต่อ SQL ที่ปล่อยออกมาสำหรับการจับคู่ในคอลัมน์ประเภท นอกจากนี้หากไม่มี 'require_dependency' คุณสามารถจบลงในสถานการณ์ที่มีคลาสโมเดลหลายรุ่นพร้อมกัน! (เช่นสิ่งนี้สามารถเกิดขึ้นได้เมื่อคุณเปลี่ยนคลาสพื้นฐานหรือคลาสกลางคลาสย่อยดูเหมือนจะไม่โหลดซ้ำและเหลือคลาสย่อยจากคลาสเก่า)

# contact.rb
class Contact < ActiveRecord::Base
  acts_as_castable
end

require_dependency 'person'
require_dependency 'organisation'

ฉันไม่ได้แทนที่ model_name ตามที่แนะนำข้างต้นเพราะฉันใช้ I18n และต้องการสตริงที่แตกต่างกันสำหรับแอตทริบิวต์ของคลาสย่อยที่แตกต่างกันเช่น tax_identifier กลายเป็น 'ABN' สำหรับองค์กรและ 'TFN' สำหรับบุคคล (ในออสเตรเลีย)

ฉันยังใช้การจับคู่เส้นทางตามที่แนะนำข้างต้นตั้งค่าประเภท:

resources :person, :controller => 'contacts', :defaults => { 'contact' => { 'type' => Person.sti_name } }
resources :organisation, :controller => 'contacts', :defaults => { 'contact' => { 'type' => Organisation.sti_name } }

นอกเหนือจากการแมปเส้นทางฉันใช้ InheritedResources และ SimpleForm และฉันใช้ wrapper แบบทั่วไปต่อไปนี้สำหรับการดำเนินการใหม่:

simple_form_for resource, as: resource_request_name, url: collection_url,
      html: { class: controller_name, multipart: true }

... และสำหรับการแก้ไขการกระทำ:

simple_form_for resource, as: resource_request_name, url: resource_url,
      html: { class: controller_name, multipart: true }

และเพื่อให้การทำงานนี้ใน ResourceContoller พื้นฐานของฉันฉันเปิดเผยของ resource_request_name ของ InheritedResource เป็นวิธีการช่วยเหลือสำหรับมุมมอง:

helper_method :resource_request_name 

หากคุณไม่ได้ใช้ InheritedResources ให้ใช้สิ่งต่อไปนี้ใน 'ResourceController' ของคุณ:

# controllers/resource_controller.rb
class ResourceController < ApplicationController

protected
  helper_method :resource
  helper_method :resource_url
  helper_method :collection_url
  helper_method :resource_request_name

  def resource
    @model
  end

  def resource_url
    polymorphic_path(@model)
  end

  def collection_url
    polymorphic_path(Model)
  end

  def resource_request_name
    ActiveModel::Naming.param_key(Model)
  end
end

มีความสุขเสมอที่จะได้ยินประสบการณ์และการปรับปรุงอื่น ๆ


จากประสบการณ์ของฉัน (อย่างน้อยใน Rails 3.0.9) ค่าคงที่ล้มเหลวหากค่าคงที่ที่ระบุโดยสตริงไม่มีอยู่ ดังนั้นจะสามารถใช้เพื่อสร้างสัญลักษณ์ใหม่โดยพลการได้อย่างไร?
Lex Lindsey

4

เมื่อเร็ว ๆ นี้ฉันได้บันทึกความพยายามในการทำให้รูปแบบ STI ที่เสถียรทำงานในแอพ Rails 3.0 นี่คือรุ่น TL; DR:

# app/controllers/kase_controller.rb
class KasesController < ApplicationController

  def new
    setup_sti_model
    # ...
  end

  def create
    setup_sti_model
    # ...
  end

private

  def setup_sti_model
    # This lets us set the "type" attribute from forms and querystrings
    model = nil
    if !params[:kase].blank? and !params[:kase][:type].blank?
      model = params[:kase].delete(:type).constantize.to_s
    end
    @kase = Kase.new(params[:kase])
    @kase.type = model
  end
end

# app/models/kase.rb
class Kase < ActiveRecord::Base
  # This solves the `undefined method alpha_kase_path` errors
  def self.inherited(child)
    child.instance_eval do
      def model_name
        Kase.model_name
      end
    end
    super
  end  
end

# app/models/alpha_kase.rb
# Splitting out the subclasses into separate files solves
# the `uninitialize constant AlphaKase` errors
class AlphaKase < Kase; end

# app/models/beta_kase.rb
class BetaKase < Kase; end

# config/initializers/preload_sti_models.rb
if Rails.env.development?
  # This ensures that `Kase.subclasses` is populated correctly
  %w[kase alpha_kase beta_kase].each do |c|
    require_dependency File.join("app","models","#{c}.rb")
  end
end

วิธีการนี้จะแก้ไขปัญหาที่คุณระบุไว้รวมถึงปัญหาอื่น ๆ ที่ผู้อื่นเคยมีเมื่อใช้วิธี STI


2

คุณสามารถลองสิ่งนี้หากคุณไม่มีเส้นทางซ้อนกัน:

resources :employee, path: :person, controller: :person

หรือคุณสามารถไปทางอื่นและใช้ OOP-magic อย่างที่อธิบายไว้ที่นี่: https://coderwall.com/p/yijmuq

ด้วยวิธีที่สองคุณสามารถสร้างผู้ช่วยที่คล้ายกันสำหรับโมเดลที่ซ้อนกันทั้งหมดของคุณ


2

นี่เป็นวิธีที่ปลอดภัยที่จะใช้งานได้ในรูปแบบและตลอดทั้งแอปพลิเคชันของคุณที่เราใช้

resources :districts
resources :district_counties, controller: 'districts', type: 'County'
resources :district_cities, controller: 'districts', type: 'City'

จากนั้นฉันก็มีรูปแบบของฉัน ชิ้นที่เพิ่มเข้ามาสำหรับสิ่งนี้คือ:: district

= form_for(@district, as: :district, html: { class: "form-horizontal",         role: "form" }) do |f|

หวังว่านี่จะช่วยได้


2

วิธีแก้ปัญหาที่สะอาดที่สุดที่ฉันพบคือการเพิ่มสิ่งต่อไปนี้ลงในคลาสฐาน:

def self.inherited(subclass)
  super

  def subclass.model_name
    super.tap do |name|
      route_key = base_class.name.underscore
      name.instance_variable_set(:@singular_route_key, route_key)
      name.instance_variable_set(:@route_key, route_key.pluralize)
    end
  end
end

มันใช้งานได้กับคลาสย่อยทั้งหมดและปลอดภัยกว่าการแทนที่ออบเจ็กต์ชื่อรุ่นทั้งหมด โดยการกำหนดเป้าหมายเฉพาะคีย์เส้นทางเราจะแก้ปัญหาการเราต์โดยไม่ทำลาย I18n หรือเสี่ยงต่อผลข้างเคียงที่อาจเกิดขึ้นจากการแทนที่ชื่อรุ่นตามที่กำหนดโดย Rails


1

ถ้าฉันพิจารณามรดกของ STI เช่นนี้:

class AModel < ActiveRecord::Base ; end
class BModel < AModel ; end
class CModel < AModel ; end
class DModel < AModel ; end
class EModel < AModel ; end

ใน 'app / models / a_model.rb' ฉันเพิ่ม:

module ManagedAtAModelLevel
  def model_name
    AModel.model_name
  end
end

แล้วในคลาส AModel:

class AModel < ActiveRecord::Base
  def self.instanciate_STI
    managed_deps = { 
      :b_model => true,
      :c_model => true,
      :d_model => true,
      :e_model => true
    }
    managed_deps.each do |dep, managed|
      require_dependency dep.to_s
      klass = dep.to_s.camelize.constantize
      # Inject behavior to be managed at AModel level for classes I chose
      klass.send(:extend, ManagedAtAModelLevel) if managed
    end
  end

  instanciate_STI
end

ดังนั้นฉันสามารถเลือกรูปแบบที่ฉันต้องการใช้ค่าเริ่มต้นได้อย่างง่ายดายและสิ่งนี้โดยไม่ต้องสัมผัสคำจำกัดความของคลาสย่อย แห้งมาก ๆ.


1

วิธีนี้ใช้ได้กับฉัน ok (กำหนดวิธีนี้ในคลาสฐาน):

def self.inherited(child)
  child.instance_eval do
    alias :original_model_name :model_name
    def model_name
      Task::Base.model_name
    end
  end
  super
end

1

คุณสามารถสร้างวิธีการที่ส่งกลับวัตถุแม่จำลองสำหรับการกำหนดเส้นทาง purpouse

class Person < ActiveRecord::Base      
  def routing_object
    Person.new(id: id)
  end
end

จากนั้นก็เรียก form_for @ employee.routing_object ซึ่งไม่มีประเภทจะส่งคืนออบเจ็กต์คลาสบุคคล


1

การติดตาม @ prathan-thananart คำตอบและสำหรับคลาส STI หลายรายการคุณสามารถเพิ่มรายการต่อไปนี้ในโมเดลหลัก ->

class Contact < ActiveRecord::Base
  def self.model_name
    ActiveModel::Name.new(self, nil, 'Contact')
  end
end

ที่จะทำให้รูปแบบที่มีข้อมูลการติดต่อแต่ละที่จะส่ง params เป็นparams[:contact]แทน,params[:contact_person]params[:contact_whatever]


-6

แฮ็ค แต่เพียงอีกหนึ่งรายการของการแก้ปัญหา

class Parent < ActiveRecord::Base; end

Class Child < Parent
  def class
    Parent
  end
end

ทำงานบนราง 2.x และ 3.x


5
วิธีนี้ช่วยแก้ไขปัญหาหนึ่ง แต่สร้างอีกปัญหาหนึ่ง ตอนนี้เมื่อคุณพยายามที่จะChild.newคืนค่าParentคลาสแทนคลาสย่อย ซึ่งหมายความว่าคุณไม่สามารถสร้างคลาสย่อยผ่านการมอบหมายจำนวนมากผ่านตัวควบคุม (เนื่องจากtypeเป็นแอตทริบิวต์ที่ได้รับการป้องกันตามค่าเริ่มต้น) เว้นแต่คุณจะตั้งค่าประเภทแอตทริบิวต์อย่างชัดเจน
Chris Bloom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.