ruby on rails - एक ही मॉडल पर कई संघों के साथ रेल पॉलीमोर्फिक एसोसिएशन




ruby-on-rails polymorphic-associations (7)

मेरा सवाल अनिवार्य रूप से वही है: पॉलिमॉर्फिक एसोसिएशन एक ही मॉडल पर कई संघों के साथ

हालांकि, प्रस्तावित / स्वीकृत समाधान काम नहीं करता है, जैसा कि बाद में एक टिप्पणीकर्ता द्वारा दिखाया गया है।

मेरे पास एक फोटो क्लास है जिसका उपयोग मेरे ऐप पर किया जाता है। एक पोस्ट में एक फोटो हो सकता है। हालांकि, मैं माध्यमिक तस्वीर जोड़ने के लिए बहुलक संबंधों का दोबारा उपयोग करना चाहता हूं।

पहले:

class Photo 
   belongs_to :attachable, :polymorphic => true
end

class Post
   has_one :photo, :as => :attachable, :dependent => :destroy
end

चाहा हे:

class Photo 
   belongs_to :attachable, :polymorphic => true
end

class Post
   has_one :photo,           :as => :attachable, :dependent => :destroy
   has_one :secondary_photo, :as => :attachable, :dependent => :destroy
end

हालांकि, यह विफल रहता है क्योंकि यह कक्षा "माध्यमिक फोटो" नहीं ढूंढ सकता है। उस अन्य धागे से मैं जो कह सकता हूं उसके आधार पर, मैं करना चाहता हूं:

   has_one :secondary_photo, :as => :attachable, :class_name => "Photo", :dependent => :destroy

कॉलिंग को छोड़कर # माध्यमिक_फोटो बस उसी फोटो को लौटाता है जो फोटो एसोसिएशन के माध्यम से जुड़ा हुआ है, उदाहरण के लिए पोस्ट # फोटो === पोस्ट # माध्यमिक_फोटो। एसक्यूएल को देखते हुए, यह कहता है कि "माध्यमिक फोटो" जैसा कि मैं चाहता हूं, इसके बजाय टाइप = "फोटो" कहां ...

विचार? धन्यवाद!

https://code.i-harness.com


मोंगोइड के लिए इस समाधान का उपयोग करें

इस मुद्दे की खोज के बाद कठिन समय था लेकिन काम करने के लिए अच्छा समाधान मिला

अपने Gemfile में जोड़ें

मणि 'mongoid-बहु-polymorphic'

और यह एक आकर्षण की तरह काम करता है:

  class Resource

  has_one :icon, as: :assetable, class_name: 'Asset', dependent: :destroy, autosave: true
  has_one :preview, as: :assetable, class_name: 'Asset', dependent: :destroy, autosave: true

  end

आपके पास बंदरगाह को विदेशी_टाइप की धारणा को हैसोन रिलेशनशिप में पैच करना होगा। यह है कि मैंने has_many के लिए किया था। आपके शुरुआती फ़ोल्डर में एक नई। आरबी फ़ाइल में मैंने अपना add_foreign_type_support.rb कहा है, यह आपको यह निर्दिष्ट करने देता है कि आपका अनुलग्नक_टाइप क्या है। उदाहरण: has_many photo,: class_name => "चित्र",: as => अनुलग्ननीय,: विदेशी_type => 'Pic'

module ActiveRecord
  module Associations
    class HasManyAssociation < AssociationCollection #:nodoc:
      protected
        def construct_sql
          case
            when @reflection.options[:finder_sql]
              @finder_sql = interpolate_sql(@reflection.options[:finder_sql])
           when @reflection.options[:as]
              resource_type = @reflection.options[:foreign_type].to_s.camelize || @owner.class.base_class.name.to_s
              @finder_sql =  "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND "
              @finder_sql += "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(resource_type)}"
              else
                @finder_sql += ")"
              end
              @finder_sql << " AND (#{conditions})" if conditions

            else
              @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
              @finder_sql << " AND (#{conditions})" if conditions
          end

          if @reflection.options[:counter_sql]
            @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
          elsif @reflection.options[:finder_sql]
            # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
            @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" }
            @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
          else
            @counter_sql = @finder_sql
          end
        end
    end
  end
end
# Add foreign_type to options list
module ActiveRecord
  module Associations # :nodoc:
     module ClassMethods
      private
        mattr_accessor :valid_keys_for_has_many_association
        @@valid_keys_for_has_many_association = [
          :class_name, :table_name, :foreign_key, :primary_key, 
          :dependent,
          :select, :conditions, :include, :order, :group, :having, :limit, :offset,
          :as, :foreign_type, :through, :source, :source_type,
          :uniq,
          :finder_sql, :counter_sql,
          :before_add, :after_add, :before_remove, :after_remove,
          :extend, :readonly,
          :validate, :inverse_of
        ]

    end
  end

क्या आप एक माध्यमिक फोटो मॉडल जोड़ सकते हैं जैसे:

class SecondaryPhoto < Photo
end

और फिर has_one से class_name को छोड़ दें: द्वितीयक_फोटो?


क्वेरीिंग के लिए निम्नलिखित कुछ काम करने के लिए काम किया, लेकिन उपयोगकर्ता से पते पर असाइन करना काम नहीं किया

उपयोगकर्ता कक्षा

has_many :addresses, as: :address_holder
has_many :delivery_addresses, -> { where :address_holder_type => "UserDelivery" },
       class_name: "Address", foreign_key: "address_holder_id"

पता कक्षा

belongs_to :address_holder, polymorphic: true

मैंने अपनी परियोजना में ऐसा किया है।

चाल यह है कि फ़ोटो को एक कॉलम की आवश्यकता होती है जिसका उपयोग प्राथमिक और माध्यमिक फ़ोटो के बीच अंतर करने के लिए हैसोन स्थिति में किया जाएगा। इसमें क्या होता है इस पर ध्यान दें :conditions यहां :conditions

has_one :photo, :as => 'attachable', 
        :conditions => {:photo_type => 'primary_photo'}, :dependent => :destroy

has_one :secondary_photo, :class_name => 'Photo', :as => 'attachable',
        :conditions => {:photo_type => 'secondary_photo'}, :dependent => :destroy

इस दृष्टिकोण की सुंदरता यह है कि जब आप @post.build_photo का उपयोग करके फ़ोटो बनाते हैं, तो फोटो_टाइप स्वचालित रूप से इसी प्रकार के साथ पूर्व-पॉप्युलेट हो जाएगा, जैसे 'primary_photo'। ActiveRecord ऐसा करने के लिए पर्याप्त स्मार्ट है।


मैंने इसका उपयोग नहीं किया, लेकिन मैंने चारों ओर गुगल किया और रेल स्रोतों में देखा और मुझे लगता है कि आप जो खोज रहे हैं वह है :foreign_type । इसे आज़माएं और बताएं कि यह काम करता है :)

has_one :secondary_photo, :as => :attachable, :class_name => "Photo", :dependent => :destroy, :foreign_type => 'SecondaryPost'

मुझे लगता है कि आपके प्रश्न में टाइप Photo बजाय Post होना चाहिए और क्रमशः, Post मॉडल को आवंटित SecondaryPost Post का उपयोग करना बेहतर होगा।

संपादित करें:

उपरोक्त उत्तर पूरी तरह से गलत है। :foreign_type संबंधित मॉडल के प्रकार वाले कॉलम के नाम को निर्दिष्ट करने के लिए belongs_to to एसोसिएशन में belongs_to मॉडल में उपलब्ध है।

जैसा कि मैं रेल स्रोतों में देखता हूं, यह लाइन एसोसिएशन के लिए इस प्रकार को सेट करती है:

dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]

जैसा कि आप देख सकते हैं कि यह टाइप नाम प्राप्त करने के लिए base_class.name का उपयोग करता है। जहां तक ​​मुझे पता है कि आप इसके साथ कुछ नहीं कर सकते हैं।

तो मेरा photo_type फोटो मॉडल में एक कॉलम जोड़ना है, उदाहरण के लिए: photo_type । और अगर यह पहली तस्वीर है, तो इसे 0 पर सेट करें, या अगर यह दूसरी तस्वीर है तो इसे 1 पर सेट करें। अपने एसोसिएशन में जोड़ें :conditions => {:photo_type => 0} और :conditions => {:photo_type => 1} क्रमशः। मुझे पता है कि यह कोई समाधान नहीं है जिसे आप ढूंढ रहे हैं, लेकिन मुझे कुछ भी बेहतर नहीं मिल रहा है। वैसे, शायद has_many एसोसिएशन का उपयोग करना बेहतर होगा?


इस पोस्ट की जांच करने वाले लोगों के लिए भविष्य का संदर्भ

यह निम्नलिखित कोड का उपयोग करके हासिल किया जा सकता है ...

रेल 3:

has_one :banner_image, conditions: { attachable_type: 'ThemeBannerAttachment' }, class_name: 'Attachment', foreign_key: 'attachable_id', dependent: :destroy

रेल 4:

has_one :banner_image, -> { where attachable_type: 'ThemeBannerAttachment'}, class_name: 'Attachment', dependent: :destroy

यकीन नहीं क्यों, लेकिन रेल 3 में, आपको शर्तों और class_name के साथ एक विदेशी_की मूल्य की आपूर्ति करने की आवश्यकता है। 'As:: attachable' का उपयोग न करें क्योंकि यह पॉलिमॉर्फिक प्रकार को सेट करते समय स्वचालित रूप से कॉलिंग क्लास नाम का उपयोग करेगा।

उपरोक्त है has_many पर भी लागू होता है।





polymorphic-associations