acts_more_seo 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -19,4 +19,6 @@ Backward compatibility improvements
19
19
  = Version 0.3.1
20
20
  * Dependencies fix
21
21
  = Version 0.3.2
22
- * Downcase fix
22
+ * Downcase fix
23
+ = Version 0.4.0
24
+ * Seo url history support for updating and searching
data/Manifest CHANGED
@@ -7,6 +7,11 @@ Rakefile
7
7
  acts_more_seo.gemspec
8
8
  init.rb
9
9
  lib/acts_more_seo.rb
10
+ lib/generators/acts_more_seo/install_generator.rb
11
+ lib/generators/acts_more_seo/templates/create_seo_history_migration.rb
12
+ lib/seo_finder.rb
13
+ lib/seo_formatter.rb
14
+ lib/seo_history.rb
10
15
  lib/string_ext.rb
11
16
  spec/acts_more_seo_spec.rb
12
17
  spec/spec_helper.rb
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  gem install acts_more_seo
6
6
 
7
7
  and in your Gemfile:
8
-
8
+
9
9
  gem 'acts_more_seo'
10
10
 
11
11
  ## About
@@ -36,7 +36,7 @@ You can also pass an array of columns like this
36
36
  })
37
37
  cool_element_path(mod) ===> cool_elements/12345-maciej-mensfeld-cool-stuff
38
38
 
39
- Further more - if you don't want to use na ID in your urls, just set use_id param to false
39
+ Further more - if you don't want to use an ID in your urls, just set use_id param to false
40
40
 
41
41
  class CoolElement < ActiveRecord::Base
42
42
  acts_more_seo :columns => [:name, :surname, :title], :use_id => false
@@ -45,7 +45,7 @@ Further more - if you don't want to use na ID in your urls, just set use_id para
45
45
  mod = CoolElement.create({
46
46
  :name => 'Maciej',
47
47
  :surname => 'Mensfeld',
48
- :title => 'cool stuuf :)'
48
+ :title => 'cool stuff :)'
49
49
  })
50
50
  cool_element_path(mod) ===> cool_elements/maciej-mensfeld-cool-stuff
51
51
 
@@ -59,8 +59,20 @@ so you can search via seo method:
59
59
 
60
60
  You don't need to update seo_url, gem will hook up with this field automatically if it exists.
61
61
 
62
+ If you want to maintain your urls history, run:
63
+
64
+ rails generate acts_more_seo:install
65
+
66
+ In order to create a SeoHistory table which will contain your urls history. History will be searchable (you don't need to do anything), just inform acts_more_seo that you want to use history:
67
+
68
+ class HisElement < ActiveRecord::Base
69
+ acts_more_seo :column => :name, :use_id => false, :history => true
70
+ end
71
+
72
+ After that, you can use find_by_seo and it will search also though the urls history.
73
+
62
74
  ## Note on Patches/Pull Requests
63
-
75
+
64
76
  * Fork the project.
65
77
  * Make your feature addition or bug fix.
66
78
  * Add tests for it. This is important so I don't break it in a future version unintentionally.
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  require 'rake'
4
4
  require 'echoe'
5
5
 
6
- Echoe.new('acts_more_seo', '0.3.2') do |p|
6
+ Echoe.new('acts_more_seo', '0.4.0') do |p|
7
7
  p.description = "Gem makes your ActiveRecord models more SEO friendly. Changes URL to look way better"
8
8
  p.url = "https://github.com/mensfeld/Css-Image-Embedder"
9
9
  p.author = "Maciej Mensfeld"
@@ -1,22 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{acts_more_seo}
5
- s.version = "0.3.2"
4
+ s.name = "acts_more_seo"
5
+ s.version = "0.4.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
- s.authors = [%q{Maciej Mensfeld}]
9
- s.date = %q{2011-12-17}
10
- s.description = %q{Gem makes your ActiveRecord models more SEO friendly. Changes URL to look way better}
11
- s.email = %q{maciej@mensfeld.pl}
12
- s.extra_rdoc_files = [%q{CHANGELOG.rdoc}, %q{README.md}, %q{lib/acts_more_seo.rb}, %q{lib/string_ext.rb}]
13
- s.files = [%q{CHANGELOG.rdoc}, %q{Gemfile}, %q{MIT-LICENSE}, %q{Manifest}, %q{README.md}, %q{Rakefile}, %q{acts_more_seo.gemspec}, %q{init.rb}, %q{lib/acts_more_seo.rb}, %q{lib/string_ext.rb}, %q{spec/acts_more_seo_spec.rb}, %q{spec/spec_helper.rb}]
14
- s.homepage = %q{https://github.com/mensfeld/Css-Image-Embedder}
15
- s.rdoc_options = [%q{--line-numbers}, %q{--inline-source}, %q{--title}, %q{Acts_more_seo}, %q{--main}, %q{README.md}]
16
- s.require_paths = [%q{lib}]
17
- s.rubyforge_project = %q{acts_more_seo}
18
- s.rubygems_version = %q{1.8.5}
19
- s.summary = %q{Gem makes your ActiveRecord models more SEO friendly. Changes URL to look way better}
8
+ s.authors = ["Maciej Mensfeld"]
9
+ s.date = "2012-02-25"
10
+ s.description = "Gem makes your ActiveRecord models more SEO friendly. Changes URL to look way better"
11
+ s.email = "maciej@mensfeld.pl"
12
+ s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.md", "lib/acts_more_seo.rb", "lib/generators/acts_more_seo/install_generator.rb", "lib/generators/acts_more_seo/templates/create_seo_history_migration.rb", "lib/seo_finder.rb", "lib/seo_formatter.rb", "lib/seo_history.rb", "lib/string_ext.rb"]
13
+ s.files = ["CHANGELOG.rdoc", "Gemfile", "MIT-LICENSE", "Manifest", "README.md", "Rakefile", "acts_more_seo.gemspec", "init.rb", "lib/acts_more_seo.rb", "lib/generators/acts_more_seo/install_generator.rb", "lib/generators/acts_more_seo/templates/create_seo_history_migration.rb", "lib/seo_finder.rb", "lib/seo_formatter.rb", "lib/seo_history.rb", "lib/string_ext.rb", "spec/acts_more_seo_spec.rb", "spec/spec_helper.rb"]
14
+ s.homepage = "https://github.com/mensfeld/Css-Image-Embedder"
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Acts_more_seo", "--main", "README.md"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "acts_more_seo"
18
+ s.rubygems_version = "1.8.15"
19
+ s.summary = "Gem makes your ActiveRecord models more SEO friendly. Changes URL to look way better"
20
20
 
21
21
  if s.respond_to? :specification_version then
22
22
  s.specification_version = 3
data/lib/acts_more_seo.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require "babosa"
2
2
  require "string_ext"
3
+ require "seo_formatter"
4
+ require "seo_finder"
5
+ require "seo_history"
3
6
 
4
7
  module Acts
5
8
  module MoreSeo
@@ -16,6 +19,7 @@ module Acts
16
19
 
17
20
  columns = params[:column] || params[:columns] || :name
18
21
  use_id = !params[:use_id].nil? ? params[:use_id] : true
22
+ history = params[:history] || false
19
23
 
20
24
  if columns.is_a?(Array)
21
25
  columns.collect!{|a| a.to_sym}
@@ -25,13 +29,22 @@ module Acts
25
29
 
26
30
  cattr_accessor :seo_columns
27
31
  cattr_accessor :seo_use_id
32
+ cattr_accessor :seo_history
28
33
 
29
34
  before_update :update_seo_url
30
35
  after_create :set_seo_url
31
36
 
32
37
  self.seo_columns = columns
33
-
38
+ self.seo_history = history
34
39
  self.seo_use_id = use_id
40
+
41
+ if self.seo_history
42
+ has_many :seo_histories,
43
+ :as => :seo_historable,
44
+ :dependent => :destroy,
45
+ :class_name => 'Acts::MoreSeo::SeoHistory'
46
+ end
47
+
35
48
  class_eval <<-END
36
49
  include Acts::MoreSeo::InstanceMethods
37
50
  END
@@ -52,9 +65,7 @@ module Acts
52
65
 
53
66
  # Lets return nice and smooth url
54
67
  def to_url
55
- seo_path = seo_text_part
56
- seo_path = "#{self.id}#{"-#{seo_path}" if seo_path && seo_path.length > 0}"
57
- seo_path.length > 0 ? seo_path : "#{self.id}"
68
+ Acts::MoreSeo::SeoFormatter.new(self).to_url
58
69
  end
59
70
  # Alias
60
71
  def url
@@ -62,21 +73,20 @@ module Acts
62
73
  end
63
74
 
64
75
  def to_seo
65
- if self.seo_use_id
66
- to_url
67
- else
68
- seo_link = seo_text_part.length > 0 ? seo_text_part : "#{self.id}"
69
- if !self.class.where("seo_url = ? AND id != ?", seo_link, self.id).limit(1).empty?
70
- to_url
71
- else
72
- seo_link
73
- end
74
- end
76
+ Acts::MoreSeo::SeoFormatter.new(self).to_seo
75
77
  end
76
78
 
77
79
  def update_seo_url
78
80
  if self.class.seo_url_table?
79
- self.update_column(:seo_url, to_seo)
81
+
82
+ new_url = to_seo
83
+
84
+ # Add old url to history if its different from the new one
85
+ if self.class.seo_history? && (new_url != self.seo_url)
86
+ self.seo_histories.create(:seo_url => self.seo_url)
87
+ end
88
+
89
+ self.update_column(:seo_url, new_url)
80
90
  end
81
91
  end
82
92
 
@@ -88,46 +98,24 @@ module Acts
88
98
 
89
99
  module ClassMethods
90
100
 
101
+ def seo_history?
102
+ self.seo_history && !self.seo_use_id
103
+ end
104
+
91
105
  def seo_url_table?
92
106
  self.column_names.include?("#{:seo_url}")
93
107
  end
94
108
 
95
109
  def find_by_seo!(id)
96
- if self.seo_use_id
97
- find(id)
98
- else
99
- find_by_seo_url! id, :first
100
- end
110
+ Acts::MoreSeo::Finder.new(self).search!(id)
101
111
  end
102
112
 
103
113
  def find_by_seo(id)
104
- if self.seo_use_id
105
- find_by_id(id)
106
- else
107
- find_by_seo_url id, :first
108
- end
114
+ Acts::MoreSeo::Finder.new(self).search(id)
109
115
  end
110
116
 
111
117
  end
112
118
 
113
- private
114
-
115
- def seo_text_part
116
- # If there is more than one SEO column - prepare url "text" part
117
- if self.class.seo_columns.is_a?(Array)
118
- seo_parts = self.class.seo_columns.collect do |field|
119
- el = self.send(field)
120
- el.to_url if el
121
- end
122
- seo_parts.delete_if{|el| el.to_s.length == 0}
123
- seo_path = seo_parts.join('-')
124
- else
125
- el = self.send(self.class.seo_columns)
126
- seo_path = el ? el.to_url : ''
127
- end
128
- seo_path
129
- end
130
-
131
119
  end
132
120
  end
133
121
  end
@@ -0,0 +1,13 @@
1
+ module ActsMoreSeo
2
+ class InstallGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("../templates", __FILE__)
4
+
5
+ def add_my_migration
6
+ timestamp = Time.now.strftime("%Y%m%d%H%M%S")
7
+ source = "create_seo_history_migration.rb"
8
+ target = "db/migrate/#{timestamp}_create_seo_history_migration.rb"
9
+ copy_file source, target
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ class CreateSeoHistoryMigration < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ create_table :seo_histories do |t|
5
+ t.integer :seo_historable_id
6
+ t.string :seo_historable_type
7
+ t.string :seo_url
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :seo_histories, :seo_historable_id
12
+ add_index :seo_histories, :seo_historable_type
13
+ add_index :seo_histories, :seo_url
14
+ end
15
+
16
+ def self.down
17
+ drop_table :seo_histories
18
+ end
19
+ end
data/lib/seo_finder.rb ADDED
@@ -0,0 +1,63 @@
1
+ module Acts
2
+ module MoreSeo
3
+
4
+ # Used to search for apropriate element in seo_urls or history (if included)
5
+ class Finder
6
+
7
+ def initialize(klass)
8
+ @klass = klass
9
+ end
10
+
11
+ def search(name)
12
+ ret = search_in_table(name)
13
+
14
+ if !ret && @klass.seo_history?
15
+ ret = search_in_history(name)
16
+ end
17
+
18
+ ret
19
+ end
20
+
21
+ def search!(name)
22
+ search_in_table!(name)
23
+ rescue ActiveRecord::RecordNotFound => e
24
+ if @klass.seo_history?
25
+ ret = search_in_history(name)
26
+ return ret if ret
27
+ end
28
+ raise e
29
+ end
30
+
31
+ private
32
+
33
+ # Try to find element in an instance class table
34
+ def search_in_table(name)
35
+ if @klass.seo_use_id
36
+ @klass.find_by_id(name)
37
+ else
38
+ @klass.find_by_seo_url name, :first
39
+ end
40
+ end
41
+
42
+ # Try to find element in an instance class table and raise exception
43
+ # if it failes
44
+ def search_in_table!(name)
45
+ if @klass.seo_use_id
46
+ @klass.find(name)
47
+ else
48
+ @klass.find_by_seo_url! name, :first
49
+ end
50
+ end
51
+
52
+ # Try to find element in its seo history
53
+ def search_in_history(name)
54
+ sql = 'seo_url = ? AND seo_historable_type = ?'
55
+ ret = Acts::MoreSeo::SeoHistory.where(sql, name, @klass.to_s).limit(1).first
56
+ ret = ret.seo_historable if ret
57
+ ret
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,56 @@
1
+ module Acts
2
+ module MoreSeo
3
+
4
+ class SeoFormatter
5
+
6
+ def initialize(instance)
7
+ @instance = instance
8
+ @klass = instance.class
9
+ end
10
+
11
+ def to_url
12
+ seo_path = text_part
13
+ seo_path = "#{@instance.id}#{"-#{seo_path}" if seo_path && seo_path.length > 0}"
14
+ seo_path.length > 0 ? seo_path : "#{@instance.id}"
15
+ end
16
+
17
+ def to_seo
18
+ return @to_seo if @to_seo
19
+
20
+ if @instance.seo_use_id
21
+ @to_seo = to_url
22
+ else
23
+ seo_link = text_part.length > 0 ? text_part : "#{@instance.id}"
24
+ if !@klass.where("seo_url = ? AND id != ?", seo_link, @instance.id).limit(1).empty?
25
+ @to_seo = to_url
26
+ else
27
+ @to_seo = seo_link
28
+ end
29
+ end
30
+ @to_seo
31
+ end
32
+
33
+ private
34
+
35
+ # Prepare text part of a seo url (the one without an id)
36
+ def text_part
37
+ return @seo_path if @seo_path
38
+ # If there is more than one SEO column - prepare url "text" part
39
+ if @klass.seo_columns.is_a?(Array)
40
+ seo_parts = @klass.seo_columns.collect do |field|
41
+ el = @instance.send(field)
42
+ el.to_url if el
43
+ end
44
+ seo_parts.delete_if{|el| el.to_s.length == 0}
45
+ @seo_path = seo_parts.join('-')
46
+ else
47
+ el = @instance.send(@klass.seo_columns)
48
+ @seo_path = el ? el.to_url : ''
49
+ end
50
+ @seo_path
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ module Acts
2
+ module MoreSeo
3
+
4
+ # Store the history of urls if they where changed
5
+ class SeoHistory < ActiveRecord::Base
6
+
7
+ belongs_to :seo_historable, :polymorphic => true
8
+
9
+ end
10
+
11
+ end
12
+ end
@@ -19,6 +19,10 @@ class BestElement < ActiveRecord::Base
19
19
  acts_more_seo :columns => [:name, :surname, :title], :use_id => false
20
20
  end
21
21
 
22
+ class HistorableElement < ActiveRecord::Base
23
+ acts_more_seo :columns => :name, :use_id => false, :history => true
24
+ end
25
+
22
26
  describe CoolElement do
23
27
  subject { CoolElement }
24
28
  before(:each){ subject.destroy_all }
@@ -130,7 +134,6 @@ describe SpecialElement do
130
134
  end
131
135
  end
132
136
 
133
-
134
137
  describe BestElement do
135
138
  subject { BestElement }
136
139
  before(:each){ subject.destroy_all }
@@ -228,3 +231,46 @@ describe BestElement do
228
231
  end
229
232
 
230
233
  end
234
+
235
+ describe HistorableElement do
236
+ subject { HistorableElement }
237
+ before(:each){ subject.destroy_all }
238
+
239
+ context "when we have polish letters" do
240
+ it "should turn them into global and use downcase" do
241
+ a = subject.create(:name => 'Kraj Żelaza')
242
+ a.name.to_url.should == 'kraj-zelaza'
243
+ end
244
+ end
245
+
246
+ context "when there is no name" do
247
+ it "should return only id" do
248
+ a = subject.create
249
+ a.to_param.should eql(a.id.to_s)
250
+ end
251
+ end
252
+
253
+ context "when we change element name" do
254
+ it "should be able to find it via old one also" do
255
+ a = subject.create(:name => 'Kraj Żelaza')
256
+ a.name.to_url.should == 'kraj-zelaza'
257
+
258
+ a.update_attributes(:name => 'Kraj Złota')
259
+ a.reload
260
+ subject.find_by_seo('kraj-zelaza').should eql a
261
+ subject.find_by_seo('kraj-zlota').should eql a
262
+ subject.find_by_seo('kraj-a').should eql nil
263
+ end
264
+
265
+ context "and the new seo_url looks the same as old one" do
266
+ it "should not remember it in history" do
267
+ nr = Acts::MoreSeo::SeoHistory.count
268
+ a = subject.create(:name => 'Kraj Żelaza')
269
+ a.update_attributes(:name => 'Kraj Żelaza')
270
+ nr.should eql Acts::MoreSeo::SeoHistory.count
271
+ end
272
+ end
273
+
274
+ end
275
+
276
+ end
data/spec/spec_helper.rb CHANGED
@@ -40,5 +40,15 @@ ActiveRecord::Schema.define do
40
40
  table.string :surname
41
41
  table.string :seo_url
42
42
  end
43
- end
44
43
 
44
+ create_table :historable_elements do |table|
45
+ table.string :name
46
+ table.string :seo_url
47
+ end
48
+
49
+ create_table :seo_histories do |table|
50
+ table.integer :seo_historable_id
51
+ table.string :seo_historable_type
52
+ table.string :seo_url
53
+ end
54
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_more_seo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-17 00:00:00.000000000Z
12
+ date: 2012-02-25 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: babosa
16
- requirement: &20403020 !ruby/object:Gem::Requirement
16
+ requirement: &11903760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *20403020
24
+ version_requirements: *11903760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &20402000 !ruby/object:Gem::Requirement
27
+ requirement: &11902800 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *20402000
35
+ version_requirements: *11902800
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: active_record
38
- requirement: &20401280 !ruby/object:Gem::Requirement
38
+ requirement: &11902200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *20401280
46
+ version_requirements: *11902200
47
47
  description: Gem makes your ActiveRecord models more SEO friendly. Changes URL to
48
48
  look way better
49
49
  email: maciej@mensfeld.pl
@@ -53,6 +53,11 @@ extra_rdoc_files:
53
53
  - CHANGELOG.rdoc
54
54
  - README.md
55
55
  - lib/acts_more_seo.rb
56
+ - lib/generators/acts_more_seo/install_generator.rb
57
+ - lib/generators/acts_more_seo/templates/create_seo_history_migration.rb
58
+ - lib/seo_finder.rb
59
+ - lib/seo_formatter.rb
60
+ - lib/seo_history.rb
56
61
  - lib/string_ext.rb
57
62
  files:
58
63
  - CHANGELOG.rdoc
@@ -64,6 +69,11 @@ files:
64
69
  - acts_more_seo.gemspec
65
70
  - init.rb
66
71
  - lib/acts_more_seo.rb
72
+ - lib/generators/acts_more_seo/install_generator.rb
73
+ - lib/generators/acts_more_seo/templates/create_seo_history_migration.rb
74
+ - lib/seo_finder.rb
75
+ - lib/seo_formatter.rb
76
+ - lib/seo_history.rb
67
77
  - lib/string_ext.rb
68
78
  - spec/acts_more_seo_spec.rb
69
79
  - spec/spec_helper.rb
@@ -93,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
103
  version: '1.2'
94
104
  requirements: []
95
105
  rubyforge_project: acts_more_seo
96
- rubygems_version: 1.8.5
106
+ rubygems_version: 1.8.15
97
107
  signing_key:
98
108
  specification_version: 3
99
109
  summary: Gem makes your ActiveRecord models more SEO friendly. Changes URL to look