Isolated this question into it's own rails app: and added a git repo as an example
Module:
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
Models:
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 Tests:
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
The first four tests pass and the second four fail. I think it might be a bug with rails polymorphic associations but I'm not sure how to isolate it further. Comments on my module design are also appreciated.
Best, Scott