1

この質問を独自のRailsアプリに分離し、例としてgitリポジトリを追加しました

モジュール:

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

最初の4つのテストは成功し、次の4つは失敗します。Railsのポリモーフィックな関連付けのバグかもしれないと思いますが、それをさらに分離する方法がわかりません。私のモジュール設計についてのコメントもありがたいです。

最高、スコット

4

1 に答える 1

2

コードの問題は次の場所にあります。

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たびに、db への新しいヒットが取得され、呼び出すたびuser.collection.object_idに異なる値が取得されます。

次のようなことを行うことで修正できます

def collection
  return @collection if @collection
  default_collection = self.collections.first
  default_collection ||= self.collections.create
  @collection = default_collection
end
于 2012-08-23T17:39:29.290 に答える