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
Search Repo:
Add redirectable support to acts_as_url_param
joshuabates (author)
Wed Jan 30 23:50:33 -0800 2008
commit  6c7e881cba3cd538126c818ebd76795a1183efe3
tree    4655ce56ee90d56fa0d916cd38bcd554f72211d4
parent  ec4c03f3e81b19e513e01306cc77f128350dce58
...
1
 
2
 
3
4
...
1
2
3
4
5
6
0
@@ -1,5 +1,7 @@
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)
...
6
7
8
 
 
 
 
 
9
10
11
...
13
14
15
16
17
 
 
 
 
 
18
19
20
21
22
23
24
25
26
...
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
62
63
...
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
29
30
31
32
33
34
...
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
107
108
...
159
160
161
 
162
163
 
164
165
166
167
168
169
0
@@ -6,6 +6,11 @@
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 @@
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
0
0
0
0
0
0
@@ -23,39 +31,76 @@
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
0
0
@@ -114,10 +159,11 @@
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
       
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0
@@ -1 +1,16 @@
0
+class Object
0
+ # The hidden singleton lurks behind everyone
0
+ def metaclass; class << self; self; end; end
0
+ def meta_eval &blk; metaclass.instance_eval &blk; end
0
+
0
+ # Adds methods to a metaclass
0
+ def meta_def name, &blk
0
+ meta_eval { define_method name, &blk }
0
+ end
0
+
0
+ # Defines an instance method within a class
0
+ def class_def name, &blk
0
+ class_eval { define_method name, &blk }
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
0
@@ -1 +1,15 @@
0
+# redirectable_type
0
+# redirectable_id
0
+# redirectable_class
0
+# name
0
+
0
+class Redirect < ActiveRecord::Base
0
+ belongs_to :redirectable, :polymorphic => true
0
+ before_create :set_real_class
0
+
0
+ private
0
+ def set_real_class
0
+ self.redirectable_class = redirectable.class.to_s
0
+ end
0
+end
...
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 @@
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 @@
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 @@
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
...
1
 
2
3
0
@@ -1,4 +1,4 @@
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
...
16
17
18
 
 
 
 
 
 
 
19
20
21
...
16
17
18
19
20
21
22
23
24
25
26
27
28
0
@@ -16,6 +16,13 @@
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 @@
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.