public
Description: Pretty url support for Ruby on Rails applications
Homepage: http://www.caring.com
Clone URL: git://github.com/caring/acts_as_url_param.git
Add redirectable support to acts_as_url_param
joshuabates (author)
Wed Jan 30 23:50:33 -0800 2008
commit  257b6fb209bcf9104531b244961e6746debfad1f
tree    1f6deed656bb17a1a0c2ba8e1cef1645b4ec84c6
parent  946efeab6bf76168bd278c2f2e1d60e52de9c466
...
1
 
2
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,4 +1,6 @@
0
 # Include hook code here
0
+require "metaid"
0
 require "acts_as_url_param"
0
+require "redirect"
0
 require "url_utils"
0
 ActiveRecord::Base.send(:include, ActsAsUrlParam)
0
\ No newline at end of file
...
6
7
8
 
 
 
 
 
9
10
11
...
13
14
15
16
17
 
 
 
 
 
18
19
20
...
23
24
25
26
27
28
29
30
31
 
 
 
 
 
32
33
34
35
36
37
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 
 
 
 
 
 
 
 
 
 
 
 
54
 
 
 
 
 
 
 
 
55
56
57
58
59
60
61
...
114
115
116
117
 
118
119
 
120
 
121
122
123
...
6
7
8
9
10
11
12
13
14
15
16
...
18
19
20
 
 
21
22
23
24
25
26
27
28
...
31
32
33
 
 
 
 
34
 
35
36
37
38
39
40
 
 
 
 
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
 
104
105
106
...
159
160
161
 
162
163
 
164
165
166
167
168
169
0
@@ -6,6 +6,11 @@ module ActsAsUrlParam
0
   module ActMethods
0
     
0
     def acts_as_url_param(*args, &block)
0
+ extend ClassMethods
0
+ include InstanceMethods
0
+ include Caring::Utilities::UrlUtils
0
+ extend Caring::Utilities::UrlUtils
0
+
0
       class_inheritable_accessor :acts_as_url_options, :acts_as_url_param_base
0
       # No extract options in rails 1.2.x
0
       options = args.respond_to?(:extract_options!) ? args.extract_options! : extract_options_from_args!(args)
0
@@ -13,8 +18,11 @@ module ActsAsUrlParam
0
       options[:column] = args.first || 'url_name'
0
       options[:from] ||= default_from_column
0
       
0
- # This won't work, as the from could be a method, and it would have to be defined before acts_as_url_param
0
- # raise ArgumentError, "No columns found to use for setting the url_param" unless column_or_method_exists? options[:from]
0
+ if options[:redirectable]
0
+ options[:on] ||= :update
0
+ make_redirectable
0
+ end
0
+
0
       options[:on] ||= :create
0
       options[:block] = block if block_given?
0
       callback = "before_validation"
0
@@ -23,39 +31,76 @@ module ActsAsUrlParam
0
         before_validation :set_url_param_if_non_existant
0
       end
0
       send callback, :set_url_param
0
- extend ClassMethods
0
- include InstanceMethods
0
- include Caring::Utilities::UrlUtils
0
- extend Caring::Utilities::UrlUtils
0
       validates_presence_of(options[:from], :if => :empty_param?) unless options[:allow_blank]
0
- self.acts_as_url_options = options
0
+
0
+ define_finder
0
+ define_url_param_setter
0
+ define_availability_check
0
+
0
       self.class_eval do
0
- define_method("#{options[:column]}=") do |value|
0
- write_attribute(options[:column], url_safe(value))
0
- end
0
-
0
         alias_method_chain :validate, :unique_url unless method_defined? :validate_without_unique_url
0
       end
0
+ end
0
+
0
+ private
0
+
0
+ def make_redirectable
0
+ has_many :redirects, :as => :redirectable
0
+ before_save :add_redirect
0
+
0
+ class_def :add_redirect do
0
+ if @name_changed && @old_name
0
+ redirects.create(:url_name => @old_name)
0
+ end
0
+ end
0
+
0
+ meta_def :find_redirect do |name|
0
+ redirect = Redirect.find(:all, :conditions => ["redirectable_class = ? AND url_name = ?", self.class.to_s, name])
0
+ redirect.redirectable if redirect
0
+ end
0
+ end
0
+
0
+ def define_finder
0
+ meta_def :find_by_url do |*args|
0
+ send("find_by_#{acts_as_url_options[:column]}", *args)
0
+ end
0
+ end
0
+
0
+ def define_url_param_setter
0
+ class_def "#{acts_as_url_options[:column]}=" do |value|
0
+ @url_name_manually_set = true if value
0
+ @old_name = read_attribute(acts_as_url_options[:column])
0
+ write_attribute(acts_as_url_options[:column], url_safe(value))
0
+ @name_changed = true unless read_attribute(acts_as_url_options[:column]) == @old_name || !@old_name
0
+ end
0
+ end
0
+
0
+ def define_availability_check
0
       klass = self
0
- (class << self; self; end).module_eval do
0
- define_method(:url_param_available_for_model?) do |*args|
0
- candidate, id = *args
0
- conditions = acts_as_url_options[:conditions] + ' AND ' if acts_as_url_options[:conditions]
0
- conditions ||= ''
0
- conditions += "#{acts_as_url_options[:column]} = ?"
0
- conditions += " AND id != ?" if id
0
- conditions = [conditions, candidate]
0
- conditions << id if id
0
- if descends_from_active_record? or self == klass
0
- count(:conditions => conditions) == 0
0
- else
0
- base_class.count(:conditions => conditions) == 0
0
- end
0
+ meta_def :url_param_available_for_model? do |*args|
0
+ candidate, id = *args
0
+ conditions = acts_as_url_options[:conditions] + ' AND ' if acts_as_url_options[:conditions]
0
+ conditions ||= ''
0
+ conditions += "#{acts_as_url_options[:column]} = ?"
0
+ conditions += " AND id != ?" if id
0
+ conditions = [conditions, candidate]
0
+ conditions << id if id
0
+ available = if descends_from_active_record? or self == klass
0
+ count(:conditions => conditions) == 0
0
+ else
0
+ base_class.count(:conditions => conditions) == 0
0
         end
0
+ if acts_as_url_options[:redirectable] && available
0
+ re_conditions = "url_name = ? AND redirectable_class = ?"
0
+ re_conditions += "AND redirectable_id != ?" if id
0
+ re_conditions = [re_conditions, candidate, self.to_s]
0
+ re_conditions << id if id
0
+ available = Redirect.count(:conditions => re_conditions) == 0
0
+ end
0
+ available
0
       end
0
     end
0
     
0
- private
0
     def default_from_column
0
       %W(name label title).detect do |column_name|
0
         column_or_method_exists?(column_name) and self.acts_as_url_options[:to].to_s != column_name
0
@@ -114,10 +159,11 @@ module ActsAsUrlParam
0
       end
0
       
0
       def set_url_param
0
- if url_param.blank? or acts_as_url_options[:on] != :create
0
+ if url_param.blank? or (acts_as_url_options[:on] != :create && !@url_name_manually_set)
0
           url = compute_url_param
0
- write_attribute(acts_as_url_options[:column], url) unless url.blank?
0
+ send("#{acts_as_url_options[:column]}=", url) unless url.blank?
0
         end
0
+ @url_name_manually_set = false
0
         @url_param_validated = true
0
       end
0
       
...
13
14
15
 
 
 
 
 
16
17
18
...
67
68
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
71
72
...
96
97
98
99
 
100
101
102
...
13
14
15
16
17
18
19
20
21
22
23
...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
121
122
123
 
124
125
126
127
0
@@ -13,6 +13,11 @@ require "story"
0
 
0
 class ActsAsUrlParamTest < Test::Unit::TestCase
0
   
0
+ def test_should_define_finder
0
+ item = ActsAsUrlParam::Item.create(:name => 'just try and find me')
0
+ assert_equal item, ActsAsUrlParam::Item.find_by_url(item.to_param)
0
+ end
0
+
0
   def test_should_set_url_name_on_create
0
     assert !ActsAsUrlParam::Item.create(:name => 'test a url param').url_name.blank?
0
   end
0
@@ -67,6 +72,26 @@ class ActsAsUrlParamTest < Test::Unit::TestCase
0
     assert_not_equal new_post.compute_url_param, story.to_param
0
   end
0
   
0
+ def test_should_create_redirect_trail
0
+ name = "this is a redirectable item"
0
+ item = ActsAsUrlParam::Item.create(:name => name)
0
+ url = item.url_name
0
+ assert_equal 0, item.redirects.size
0
+ item.update_attributes :name => "redirect to me"
0
+ item.reload
0
+ assert_equal 1, item.redirects.count
0
+ assert_equal url, item.redirects.first.url_name
0
+ end
0
+
0
+ def test_should_check_redirects_table_for_available_names
0
+ name = "this is a redirectable item"
0
+ item = ActsAsUrlParam::Book.create(:name => name)
0
+ url = item.url_name
0
+ item.update_attributes(:name => "second one")
0
+ assert !ActsAsUrlParam::Book.url_param_available?(url)
0
+ assert ActsAsUrlParam::Magazine.url_param_available?(url)
0
+ end
0
+
0
   def test_should_compute_url_name
0
     name = 'this is a url param'
0
     item = ActsAsUrlParam::Item.new(:name => name)
0
@@ -96,7 +121,7 @@ class ActsAsUrlParamTest < Test::Unit::TestCase
0
   end
0
 
0
   def test_should_not_update_url_name_by_default
0
- item = ActsAsUrlParam::Item.create(:name => 'this is a url param')
0
+ item = ActsAsUrlParam::Newspaper.create(:name => 'this is a url param')
0
     item_url = item.to_param
0
     item.update_attributes(:name => 'not updated')
0
     assert_equal(item_url, item.to_param)
...
1
2
 
3
4
...
1
 
2
3
4
0
@@ -1,3 +1,3 @@
0
 class ActsAsUrlParam::Item < ActsAsUrlParamBase
0
- acts_as_url_param :conditions => "items.type != 'Newspaper'"
0
+ acts_as_url_param :conditions => "items.type != 'Newspaper'", :redirectable => true
0
 end
0
\ No newline at end of file
...
16
17
18
 
 
 
 
 
 
 
19
20
21
...
16
17
18
19
20
21
22
23
24
25
26
27
28
0
@@ -16,6 +16,13 @@ ActiveRecord::Schema.define() do
0
     t.column :url_name, :string
0
   end
0
   
0
+ create_table :redirects do |t|
0
+ t.column :redirectable_type, :string
0
+ t.column :redirectable_id, :integer
0
+ t.column :redirectable_class, :string
0
+ t.column :url_name, :string
0
+ end
0
+
0
   create_table :stories do |t|
0
     t.column :title, :string
0
     t.column :story_url, :string
...
35
36
37
 
 
 
38
39
40
...
35
36
37
38
39
40
41
42
43
0
@@ -35,6 +35,9 @@ end
0
 
0
 ActiveRecord::Base.connected? ? keep_connection_and_load_schema.call : load_schema.call
0
 
0
+require "redirect"
0
+Redirect.connection = ACTS_AS_URL_PARAM_TEST_DB
0
+
0
 class Test::Unit::TestCase #:nodoc:
0
   def create_fixtures(*table_names)
0
     if block_given?

Comments

    No one has commented yet.