Commit 4bbfef7e42eff51025675d1e6f70aee7c26527ff

Authored by Rodrigo Souto
1 parent 457c9f59

article: author refactoring

I'm adding the author as a record relation instead of calculating it
based on the last_changed_by. This change has a reasonable performance
improvement on pages that access this information, like blog page.

Still saving author_name in order to deal with the problem of the author
being removed.

Including new method to facilitate specific article version retrieval.

ActionItem3201
app/controllers/my_profile/cms_controller.rb
... ... @@ -144,6 +144,7 @@ class CmsController < MyProfileController
144 144 end
145 145  
146 146 @article.profile = profile
  147 + @article.author = user
147 148 @article.last_changed_by = user
148 149  
149 150 translations if @article.translatable?
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -83,7 +83,7 @@ class ContentViewerController < ApplicationController
83 83 @page.posts
84 84 end
85 85  
86   - posts = posts.includes(:parent, {:profile => [:domains, :environment]})
  86 + posts = posts.includes(:parent, {:profile => [:domains, :environment]}, :author)
87 87  
88 88 #FIXME Need to run this before the pagination because this version of
89 89 # will_paginate returns a will_paginate collection instead of a
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -26,7 +26,7 @@ module ContentViewerHelper
26 26 end
27 27 title << content_tag('span',
28 28 content_tag('span', show_date(article.published_at), :class => 'date') +
29   - content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') +
  29 + content_tag('span', [_(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name)], :class => 'author') +
30 30 content_tag('span', comments, :class => 'comments'),
31 31 :class => 'created-at'
32 32 )
... ...
app/models/article.rb
... ... @@ -39,8 +39,8 @@ class Article &lt; ActiveRecord::Base
39 39 before_save :sanitize_tag_list
40 40  
41 41 before_create do |article|
42   - if article.last_changed_by_id
43   - article.author_name = Person.find(article.last_changed_by_id).name
  42 + if article.author
  43 + article.author_name = article.author.name
44 44 end
45 45 end
46 46  
... ... @@ -52,6 +52,7 @@ class Article &lt; ActiveRecord::Base
52 52  
53 53 validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? }
54 54  
  55 + belongs_to :author, :class_name => 'Person'
55 56 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
56 57  
57 58 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
... ... @@ -449,7 +450,7 @@ class Article &lt; ActiveRecord::Base
449 450 ['TextArticle', 'TextileArticle', 'TinyMceArticle']
450 451 end
451 452  
452   - named_scope :published, :conditions => { :published => true }
  453 + named_scope :published, :conditions => ['articles.published = ?', true]
453 454 named_scope :folders, lambda {|profile|{:conditions => ['articles.type IN (?)', profile.folder_types] }}
454 455 named_scope :no_folders, lambda {|profile|{:conditions => ['articles.type NOT IN (?)', profile.folder_types]}}
455 456 named_scope :galleries, :conditions => [ "articles.type IN ('Gallery')" ]
... ... @@ -462,7 +463,7 @@ class Article &lt; ActiveRecord::Base
462 463 named_scope :more_recent, :order => "created_at DESC"
463 464  
464 465 def self.display_filter(user, profile)
465   - return {:conditions => ['published = ?', true]} if !user
  466 + return {:conditions => ['articles.published = ?', true]} if !user
466 467 {:conditions => [" articles.published = ? OR
467 468 articles.last_changed_by_id = ? OR
468 469 articles.profile_id = ? OR
... ... @@ -621,39 +622,36 @@ class Article &lt; ActiveRecord::Base
621 622 can_display_versions? && display_versions
622 623 end
623 624  
624   - def author(version_number = nil)
625   - if version_number
626   - version = versions.find_by_version(version_number)
627   - author_id = version.last_changed_by_id if version
628   - Person.exists?(author_id) ? Person.find(author_id) : nil
629   - else
630   - if versions.empty?
631   - last_changed_by
632   - else
633   - author_id = versions.first.last_changed_by_id
634   - Person.exists?(author_id) ? Person.find(author_id) : nil
635   - end
636   - end
  625 + def get_version(version_number = nil)
  626 + version_number ? versions.find(:first, :order => 'version', :offset => version_number - 1) : versions.earliest
  627 + end
  628 +
  629 + def author_by_version(version_number = nil)
  630 + version_number ? profile.environment.people.find_by_id(get_version(version_number).last_changed_by_id) : author
637 631 end
638 632  
639 633 def author_name(version_number = nil)
640   - person = author(version_number)
641   - person ? person.name : (setting[:author_name] || _('Unknown'))
  634 + person = author_by_version(version_number)
  635 + if version_number
  636 + person ? person.name : _('Unknown')
  637 + else
  638 + person ? person.name : (setting[:author_name] || _('Unknown'))
  639 + end
642 640 end
643 641  
644 642 def author_url(version_number = nil)
645   - person = author(version_number)
  643 + person = author_by_version(version_number)
646 644 person ? person.url : nil
647 645 end
648 646  
649 647 def author_id(version_number = nil)
650   - person = author(version_number)
  648 + person = author_by_version(version_number)
651 649 person ? person.id : nil
652 650 end
653 651  
654 652 def version_license(version_number = nil)
655 653 return license if version_number.nil?
656   - profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id)
  654 + profile.environment.licenses.find_by_id(get_version(version_number).license_id)
657 655 end
658 656  
659 657 alias :active_record_cache_key :cache_key
... ...
db/migrate/20140709224246_create_real_relation_between_article_and_author.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateRealRelationBetweenArticleAndAuthor < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :articles, :author_id, :integer
  4 + add_column :article_versions, :author_id, :integer
  5 +
  6 + # Set article's author as the first version's last_changed_by_id.
  7 + execute "update articles set author_id = (select article_versions.last_changed_by_id from article_versions where article_versions.article_id = articles.id and article_versions.version = 1 limit 1)"
  8 + end
  9 +
  10 + def self.down
  11 + remove_column :articles, :author_id
  12 + remove_column :article_versions, :author_id
  13 + end
  14 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,7 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20140709212646) do
  12 +ActiveRecord::Schema.define(:version => 20140709224246) do
13 13  
14 14 create_table "abuse_reports", :force => true do |t|
15 15 t.integer "reporter_id"
... ... @@ -94,6 +94,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140709212646) do
94 94 t.integer "image_id"
95 95 t.integer "position"
96 96 t.integer "spam_comments_count", :default => 0
  97 + t.integer "author_id"
97 98 end
98 99  
99 100 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id"
... ... @@ -140,6 +141,7 @@ ActiveRecord::Schema.define(:version =&gt; 20140709212646) do
140 141 t.integer "image_id"
141 142 t.integer "position"
142 143 t.integer "spam_comments_count", :default => 0
  144 + t.integer "author_id"
143 145 end
144 146  
145 147 add_index "articles", ["comments_count"], :name => "index_articles_on_comments_count"
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -767,7 +767,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
767 767 c = Community.create!(:name => 'test_com')
768 768 u = create_user_with_permission('test_user', 'publish_content', c)
769 769 login_as u.identifier
770   - a = c.articles.create!(:name => 'test-article', :last_changed_by => u, :published => false)
  770 + a = c.articles.create!(:name => 'test-article', :author => u, :published => false)
771 771  
772 772 get :view_page, :profile => c.identifier, :page => a.explode_path
773 773  
... ... @@ -779,7 +779,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
779 779 c = Community.create!(:name => 'test_com')
780 780 u = create_user_with_permission('test_user', 'publish_content', c)
781 781 login_as u.identifier
782   - a = c.articles.create!(:name => 'test-article', :last_changed_by => profile, :published => true)
  782 + a = c.articles.create!(:name => 'test-article', :author => profile, :published => true)
783 783  
784 784 xhr :get, :view_page, :profile => c.identifier, :page => a.explode_path, :toolbar => true
785 785  
... ... @@ -926,7 +926,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
926 926 community.add_member(author)
927 927  
928 928 forum = Forum.create(:profile => community, :name => 'Forum test', :body => 'Forum test')
929   - post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :last_changed_by_id => author.id)
  929 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :author_id => author.id)
930 930  
931 931 login_as(author.identifier)
932 932 get :view_page, :profile => community.identifier, :page => post.path.split('/')
... ... @@ -942,7 +942,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
942 942 community.add_member(author)
943 943  
944 944 forum = Forum.create(:profile => community, :name => 'Forum test', :body => 'Forum test')
945   - post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :last_changed_by_id => author.id)
  945 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :author_id => author.id)
946 946  
947 947 login_as(author.identifier)
948 948 get :view_page, :profile => community.identifier, :page => post.path.split('/')
... ...
test/unit/article_test.rb
... ... @@ -802,7 +802,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
802 802 should 'allow author to edit if is publisher' do
803 803 c = fast_create(Community)
804 804 p = create_user_with_permission('test_user', 'publish_content', c)
805   - a = c.articles.create!(:name => 'a test article', :last_changed_by => p)
  805 + a = c.articles.create!(:name => 'a test article', :author => p)
806 806  
807 807 assert a.allow_post_content?(p)
808 808 end
... ... @@ -1378,7 +1378,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1378 1378  
1379 1379 should "the author_name returns the name of the article's author" do
1380 1380 author = fast_create(Person)
1381   - a = profile.articles.create!(:name => 'a test article', :last_changed_by => author)
  1381 + a = profile.articles.create!(:name => 'a test article', :author => author)
1382 1382 assert_equal author.name, a.author_name
1383 1383 author.destroy
1384 1384 a.reload
... ... @@ -1388,7 +1388,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1388 1388  
1389 1389 should 'retrieve latest info from topic when has no comments' do
1390 1390 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id)
1391   - post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now, :last_changed_by_id => profile.id)
  1391 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now, :author_id => profile.id)
1392 1392 assert_equal post.updated_at, post.info_from_last_update[:date]
1393 1393 assert_equal profile.name, post.info_from_last_update[:author_name]
1394 1394 assert_equal profile.url, post.info_from_last_update[:author_url]
... ... @@ -1668,7 +1668,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1668 1668 author = fast_create(Person)
1669 1669 community.add_member(author)
1670 1670 forum = Forum.create(:profile => community, :name => 'Forum test', :body => 'Forum test')
1671   - post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :last_changed_by_id => author.id)
  1671 + post = fast_create(TextileArticle, :name => 'First post', :profile_id => community.id, :parent_id => forum.id, :author_id => author.id)
1672 1672  
1673 1673 assert post.allow_edit?(author)
1674 1674 end
... ... @@ -1753,7 +1753,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1753 1753  
1754 1754 should 'set author_name before creating article if there is an author' do
1755 1755 author = fast_create(Person)
1756   - article = Article.create!(:name => 'Test', :profile => profile, :last_changed_by => author)
  1756 + article = Article.create!(:name => 'Test', :profile => profile, :author => author)
1757 1757 assert_equal author.name, article.author_name
1758 1758  
1759 1759 author_name = author.name
... ... @@ -1764,12 +1764,12 @@ class ArticleTest &lt; ActiveSupport::TestCase
1764 1764  
1765 1765 should "author_id return the author id of the article's author" do
1766 1766 author = fast_create(Person)
1767   - article = Article.create!(:name => 'Test', :profile => profile, :last_changed_by => author)
  1767 + article = Article.create!(:name => 'Test', :profile => profile, :author => author)
1768 1768 assert_equal author.id, article.author_id
1769 1769 end
1770 1770  
1771 1771 should "author_id return nil if there is no article's author" do
1772   - article = Article.create!(:name => 'Test', :profile => profile, :last_changed_by => nil)
  1772 + article = Article.create!(:name => 'Test', :profile => profile, :author => nil)
1773 1773 assert_nil article.author_id
1774 1774 end
1775 1775  
... ... @@ -1780,8 +1780,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
1780 1780 article.name = 'second version'
1781 1781 article.last_changed_by = author2
1782 1782 article.save
1783   - assert_equal author1, article.author(1)
1784   - assert_equal author2, article.author(2)
  1783 + assert_equal author1, article.author_by_version(1)
  1784 + assert_equal author2, article.author_by_version(2)
1785 1785 end
1786 1786  
1787 1787 should "return the author_name of a specific version" do
... ... @@ -1837,4 +1837,33 @@ class ArticleTest &lt; ActiveSupport::TestCase
1837 1837 assert_equivalent [c3], Article.with_types(['Event'])
1838 1838 end
1839 1839  
  1840 + should 'get specific version' do
  1841 + article = Article.create!(:name => 'first version', :profile => profile)
  1842 + article.name = 'second version'
  1843 + article.save!
  1844 + article.name = 'third version'
  1845 + article.save!
  1846 +
  1847 + assert_equal 'first version', article.get_version(1).name
  1848 + assert_equal 'second version', article.get_version(2).name
  1849 + assert_equal 'third version', article.get_version(3).name
  1850 + end
  1851 +
  1852 + should 'get author by version' do
  1853 + p1 = fast_create(Person)
  1854 + p2 = fast_create(Person)
  1855 + p3 = fast_create(Person)
  1856 + article = Article.create!(:name => 'first version', :profile => profile, :last_changed_by => p1)
  1857 + article.name = 'second version'
  1858 + article.last_changed_by = p2
  1859 + article.save!
  1860 + article.last_changed_by = p3
  1861 + article.name = 'third version'
  1862 + article.save!
  1863 +
  1864 + assert_equal p1, article.author_by_version(1)
  1865 + assert_equal p2, article.author_by_version(2)
  1866 + assert_equal p3, article.author_by_version(3)
  1867 + end
  1868 +
1840 1869 end
... ...