导轨和委托方法的关联。 可能的错误与AR?(Rails association with del

2019-10-17 03:46发布

隔离这个问题到它自己的Rails应用程序:并增加了一个混帐回购协议作为例子

模块:

module SeoMeta

  def self.included(base)
    base.extend(ClassMethods)
    base.send :include, InstanceMethods
  end

  module ClassMethods

    def is_seo_meta

      has_one :meta,
        class_name: SeoMetum,
        as:         :metumable,
        dependent:  :destroy,
        autosave:   true

      delegate :browser_title,     :meta_description, :meta_author,
               :meta_keywords,     :browser_title=,   :meta_keywords=,
               :meta_description=, :meta_author=,
               to: :meta

      after_save :save_meta_tags!

      attr_accessible :browser_title,    :meta_keywords,
                      :meta_description, :meta_author

    end

  end

  module InstanceMethods

    class << self
      def included(base)
        base.module_eval do

          alias :original_meta_method :meta

        end
      end
    end

    def meta
      find_meta || build_meta
    end

    def find_meta
      @meta ||= ::SeoMetum.where(metumable_type: self.class.name, metumable_id: self.id).first
    end

    def build_meta
      @meta ||= ::SeoMetum.new(metumable_type: self.class.name, metumable_id: self.id)
    end  

    def save_meta_tags!
      meta.metumable_id ||= self.id
      meta.save
    end

  end
end

楷模:

class User < ActiveRecord::Base
  include SeoMeta
  is_seo_meta

  has_many :collections
  accepts_nested_attributes_for :collections

  def collection
    default_collection = self.collections.first
    default_collection ||= self.collections.create
    default_collection
  end
end

class Collection < ActiveRecord::Base
  include SeoMeta
  is_seo_meta
  belongs_to :user

end

class SeoMetum < ActiveRecord::Base
  attr_accessible :browser_title, :meta_author, :meta_description, :meta_keywords,
                  :metumable, :metumable_id, :metumable_type
  belongs_to :metumable, polymorphic: true
end

Rspec的测试:

 context "user and collection" do
    context 'responds to' do
      it 'meta_description' do
        user.collection.respond_to?(:meta_description).should be_true
      end

      it 'browser_title' do
        user.collection.respond_to?(:browser_title).should be_true
      end
    end

    context 'individual allows us to assign to' do
      it 'meta_description' do
        the_collection = user.collection
        the_collection.meta_description = 'This is my description of the user for search results.'
        the_collection.meta_description.should == 'This is my description of the user for search results.'
      end

      it 'browser_title' do
        the_collection = user.collection
        the_collection.browser_title = 'An awesome browser title for SEO'
        the_collection.browser_title.should == 'An awesome browser title for SEO'
      end
    end


    context 'allows us to assign to' do
      it 'meta_description' do
        user.collection.meta_description = 'This is my description of the user for search results.'
        user.collection.meta_description.should == 'This is my description of the user for search results.'
      end

      it 'browser_title' do
        user.collection.browser_title = 'An awesome browser title for SEO'
        user.collection.browser_title.should == 'An awesome browser title for SEO'
      end
    end

    context 'allows us to update' do
      it 'meta_description' do
        user.collection.meta_description = 'This is my description of the user for search results.'
        user.collection.save

        user.collection.reload
        user.collection.meta_description.should == 'This is my description of the user for search results.'
      end

      it 'browser_title' do
        user.collection.browser_title = 'An awesome browser title for SEO'
        user.collection.save

        user.collection.reload
        user.collection.browser_title.should == 'An awesome browser title for SEO'
      end
    end
  end

前四个测试通过,第二个四失败。 我认为这可能是与轨道多态关联一个错误,但我不知道如何将它进一步孤立。 我模块的设计评论也很受青睐。

最好,斯科特

Answer 1:

在你的代码的问题是在这个地方:

class User
  #Other stuff

  #HERE!
  def collection
    default_collection = self.collections.first
    default_collection ||= self.collections.create
    default_collection
  end
end

每次通话时间collection方法你查找第一个集合中的数据库。 因此,即使你设置一些值user.collection.meta_description = "abc"当你调用后来user.collection它是不一样的集合对象的原因它已经从数据库中新的查找。 因此不会保存到数据库中的所有属性都没有了。 您可以通过查看日志中看到这一点-每次通话时间user.collection你得到新的命中分贝,也每次通话时间user.collection.object_id你会得到不同的值。

你可以做这样的事情修复

def collection
  return @collection if @collection
  default_collection = self.collections.first
  default_collection ||= self.collections.create
  @collection = default_collection
end


文章来源: Rails association with delegate methods. possible bug with AR?