diff --git a/app/models/topic.rb b/app/models/topic.rb index 896c6d972..0ff99cfc3 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -5,10 +5,12 @@ require_dependency 'rate_limiter' require_dependency 'text_sentinel' require_dependency 'text_cleaner' require_dependency 'archetype' +require_dependency "concern/has_custom_fields" class Topic < ActiveRecord::Base include ActionView::Helpers::SanitizeHelper include RateLimiter::OnCreateRecord + include Concern::HasCustomFields include Trashable extend Forwardable @@ -103,6 +105,7 @@ class Topic < ActiveRecord::Base attr_accessor :user_data attr_accessor :posters # TODO: can replace with posters_summary once we remove old list code attr_accessor :topic_list + attr_accessor :meta_data attr_accessor :include_last_poster # The regular order @@ -318,8 +321,16 @@ class Topic < ActiveRecord::Base topics.where("topics.id NOT IN (?)", featured_topic_ids) end + def meta_data=(data) + custom_fields.replace(data) + end + + def meta_data + custom_fields + end + def update_meta_data(data) - self.meta_data = (self.meta_data || {}).merge(data.stringify_keys) + custom_fields.update(data) save end @@ -341,8 +352,7 @@ class Topic < ActiveRecord::Base end def meta_data_string(key) - return unless meta_data.present? - meta_data[key.to_s] + custom_fields[key.to_s] end def self.listable_count_per_day(sinceDaysAgo=30) @@ -820,7 +830,6 @@ end # archived :boolean default(FALSE), not null # bumped_at :datetime not null # has_summary :boolean default(FALSE), not null -# meta_data :hstore # vote_count :integer default(0), not null # archetype :string(255) default("regular"), not null # featured_user4_id :integer diff --git a/app/models/topic_custom_field.rb b/app/models/topic_custom_field.rb new file mode 100644 index 000000000..85db5aea3 --- /dev/null +++ b/app/models/topic_custom_field.rb @@ -0,0 +1,19 @@ +class TopicCustomField < ActiveRecord::Base + belongs_to :topic +end + +# == Schema Information +# +# Table name: topic_custom_fields +# +# id :integer not null, primary key +# topic_id :integer not null +# name :string(256) not null +# value :text +# created_at :datetime +# updated_at :datetime +# +# Indexes +# +# index_topic_custom_fields_on_topic_id_and_name (topic_id,name) +# diff --git a/db/migrate/20140425135354_add_topic_custom_fields.rb b/db/migrate/20140425135354_add_topic_custom_fields.rb new file mode 100644 index 000000000..4a059f8a6 --- /dev/null +++ b/db/migrate/20140425135354_add_topic_custom_fields.rb @@ -0,0 +1,21 @@ +class AddTopicCustomFields < ActiveRecord::Migration + def change + create_table :topic_custom_fields do |t| + t.integer :topic_id, null: false + t.string :name, limit: 256, null: false + t.text :value + t.timestamps + end + + add_index :topic_custom_fields, [:topic_id, :name] + + # migrate meta_data into custom fields + execute <<-SQL + INSERT INTO topic_custom_fields(topic_id, name, value) + SELECT id, (each(meta_data)).key, (each(meta_data)).value + FROM topics WHERE meta_data <> '' + SQL + + remove_column :topics, :meta_data + end +end diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 56eca86cd..03bd04c36 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -722,6 +722,21 @@ describe Topic do end + context 'new key' do + before do + topic.update_meta_data('other' => 'key') + topic.save! + end + + it "can be loaded" do + Topic.find(topic.id).meta_data["other"].should == "key" + end + + it "is in sync with custom_fields" do + Topic.find(topic.id).custom_fields["other"].should == "key" + end + end + end @@ -1380,7 +1395,17 @@ describe Topic do topic.stubs(:has_topic_embed?).returns(false) topic.expandable_first_post?.should be_false end + end + it "has custom fields" do + topic = Fabricate(:topic) + topic.custom_fields["a"].should == nil + topic.custom_fields["bob"] = "marley" + topic.custom_fields["jack"] = "black" + topic.save + + topic = Topic.find(topic.id) + topic.custom_fields.should == {"bob" => "marley", "jack" => "black"} end end