rd_find_by_param 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,123 +1,52 @@
1
1
  begin
2
- $KCODE = 'u'
3
- require 'rubygems'
4
- require 'active_support'
2
+ require "active_support/multibyte"
5
3
  rescue LoadError
4
+ require "rubygems"
5
+ require "active_support/multibyte"
6
6
  end
7
7
 
8
8
  module Railslove
9
9
  module Plugins
10
10
  module FindByParam
11
- def self.enable # :nodoc:
12
- return if ActiveRecord::Base.kind_of?(self::ClassMethods)
13
11
 
14
- ActiveRecord::Base.class_eval do
15
- class_inheritable_accessor :permalink_options
16
- self.permalink_options = {:param => :id}
17
-
18
- #default finders these are overwritten if you use make_permalink in
19
- # your model
20
- def self.find_by_param(value,args={}) # :nodoc:
21
- find_by_id(value,args)
22
- end
23
- def self.find_by_param!(value,args={}) # :nodoc:
24
- find(value,args)
25
- end
26
- end
27
- ActiveRecord::Base.extend(self::ClassMethods)
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
28
14
  end
29
15
 
30
16
  module ClassMethods
31
17
 
32
-
33
- =begin rdoc
34
-
35
- This method initializes find_by_param
36
-
37
- class Post < ActiveRecord::Base
38
- make_permalink :with => :title, :prepend_id => true
39
- end
40
-
41
- The only required parameter, is <tt>:with</tt>.
42
-
43
- If you want to use a non URL-save attribute as permalink your model should have a permalink-column to save the escaped permalink value. This field is then used for search.
44
-
45
- If your you can just say make_permalink :with => :login and you're done.
46
-
47
- You can use for example User.find_by_param(params[:id], args) to find the user by the defined permalink.
48
-
49
- == Available options
50
-
51
- <tt>:with</tt>:: (required) The attribute that should be used as permalink
52
- <tt>:field</tt>:: The name of your permalink column. make_permalink first checks if there is a column, default is 'permalink'.
53
- <tt>:prepend_id</tt>:: [true|false] Do you want to prepend the ID to the permalink? for URLs like: posts/123-my-post-title - find_by_param uses the ID column to search, default is false.
54
- <tt>:param_size</tt>:: [Number] Desired maximum size of the permalink, default is 50.
55
- <tt>:escape</tt>:: [true|false] Do you want to escape the permalink value? (strip chars like öä?&) - actually you must do that, default is true.
56
- <tt>:validate</tt>:: [true|false] Don't validate the :with field - set this to false if you validate it on your own, default is true.
57
- <tt>:forbidden</tt>:: [Regexp|String|Array of Strings] Define which values should be forbidden. This is useful when combining user defined values to generate permalinks in combination with restful routing. <b>Make sure, especially in the case of a Regexp argument, that values may become valid by adding or incrementing a trailing integer.</b>
58
- =end
59
18
  def make_permalink(options={})
60
19
  options[:field] ||= "permalink"
61
- options[:param] = options[:with] # :with => :login - but if we have a spcific permalink column we need to set :param to the name of that column
62
- options[:escape] ||= true
63
- options[:prepend_id] ||= false
64
- options[:param_size] ||= 50
65
- options[:validate] = true if options[:validate].nil?
66
-
67
- # validate if there is something we can use as param. you can overwrite the validate_param_is_not_blank method to customize the validation and the error messge.
68
- if !options[:prepend_id] || !options[:validate]
69
- validate :validate_param_is_not_blank
70
- end
71
20
 
72
- if forbidden = options.delete(:forbidden)
73
- if forbidden.is_a? Regexp
74
- options[:forbidden_match] = forbidden
75
- else
76
- options[:forbidden_strings] = Array(forbidden).map(&:to_s)
77
- end
78
- end
21
+ self.send(:validates_uniqueness_of, options[:field])
79
22
 
80
23
  if self.column_names.include?(options[:field].to_s)
81
24
  options[:param] = options[:field]
82
- before_save :save_permalink
25
+ before_validation(:on => :create){ save_permalink }
83
26
  end
84
27
 
85
28
  self.permalink_options = options
86
29
  extend Railslove::Plugins::FindByParam::SingletonMethods
87
30
  include Railslove::Plugins::FindByParam::InstanceMethods
88
- rescue ActiveRecord::ActiveRecordError
89
- puts "[find_by_param error] database not available?"
31
+ rescue
32
+ # Database is not available (not a problem if we're running rake db:create or rake db:bootstrap)
90
33
  end
91
34
  end
92
35
 
93
36
  module SingletonMethods
94
37
 
95
- =begin rdoc
96
-
97
- Search for an object by the defined permalink column. Similar to
98
- +find_by_login+. Returns +nil+ if nothing is found. Accepts an options hash as
99
- second parameter which is passed on to the rails finder.
100
- =end
101
- def find_by_param(value, args={})
38
+ def find_by_param(value,args={})
102
39
  if permalink_options[:prepend_id]
103
40
  param = "id"
104
41
  value = value.to_i
105
42
  else
106
- param = permalink_options[:param]
43
+ param = permalink_options[:field]
107
44
  end
108
45
  self.send("find_by_#{param}".to_sym, value, args)
109
46
  end
110
47
 
111
- =begin rdoc
112
-
113
- Like +find_by_param+ but raises an <tt>ActiveRecord::RecordNotFound</tt> error
114
- if nothing is found - similar to find().
115
-
116
- Accepts an options hash as second parameter which is passed on to the rails
117
- finder.
118
- =end
119
48
  def find_by_param!(value, args={})
120
- param = permalink_options[:param]
49
+ param = permalink_options[:field]
121
50
  obj = find_by_param(value, args)
122
51
  raise ::ActiveRecord::RecordNotFound unless obj
123
52
  obj
@@ -125,77 +54,25 @@ finder.
125
54
  end
126
55
 
127
56
  module InstanceMethods
128
- def to_param
129
- value = self.send(permalink_options[:param]).dup.to_s.downcase rescue ""
130
- ''.tap do |param|
131
- if value.blank?
132
- param << id.to_s
133
- else
134
- param << "#{id}-" if permalink_options[:prepend_id]
135
- param << escape_and_truncate_permalink(value)
136
- end
137
- end
138
- end
139
57
 
140
58
  protected
141
-
142
59
  def save_permalink
143
60
  return unless self.class.column_names.include?(permalink_options[:field].to_s)
61
+ return if !changed?
62
+
63
+ base_value = to_param
64
+ permalink_value = base_value
144
65
  counter = 0
145
- base_value = escape_and_truncate_permalink(send(permalink_options[:with])).downcase
146
- permalink_value = base_value.to_s
147
66
 
148
- conditions = ["#{self.class.table_name}.#{permalink_options[:field]} = ?", permalink_value]
149
- unless new_record?
150
- conditions.first << " and #{self.class.table_name}.#{self.class.primary_key} != ?"
151
- conditions << self.send(self.class.primary_key.to_sym)
152
- end
153
- while is_forbidden?(permalink_value) or
154
- self.class.count(:all, :conditions => conditions) > 0
67
+ begin
68
+ permalink_value = base_value + ((counter == 0) ? "" : "-#{counter}")
69
+ query = self.class.send("where", "#{permalink_options[:field]} = ?", permalink_value)
155
70
  counter += 1
156
- permalink_value = "#{base_value}-#{counter}"
157
-
158
- if permalink_value.size > permalink_options[:param_size]
159
- length = permalink_options[:param_size] - counter.to_s.size - 2
160
- truncated_base = base_value[0..length]
161
- permalink_value = "#{truncated_base}-#{counter}"
162
- end
71
+ end while query.limit(1).present?
163
72
 
164
- conditions[1] = permalink_value
165
- end
166
73
  write_attribute(permalink_options[:field], permalink_value)
167
74
  true
168
- end
169
75
 
170
- def validate_param_is_not_blank
171
- if self.escape_and_truncate_permalink(self.send(permalink_options[:with])).blank?
172
- errors.add(permalink_options[:with],
173
- "must have at least one non special character (a-z 0-9)")
174
- end
175
- end
176
-
177
- def escape_permalink(value)
178
- value.to_s.parameterize
179
- end
180
-
181
- def is_forbidden?(permalink_value)
182
- is_forbidden_string?(permalink_value) ||
183
- matches_forbidden_regexp?(permalink_value)
184
- end
185
-
186
- def is_forbidden_string?(permalink_value)
187
- permalink_options[:forbidden_strings] &&
188
- permalink_options[:forbidden_strings].include?(permalink_value)
189
- end
190
-
191
- def matches_forbidden_regexp?(permalink_value)
192
- permalink_options[:forbidden_match] &&
193
- permalink_options[:forbidden_match] =~ permalink_value
194
- end
195
-
196
- def escape_and_truncate_permalink(value)
197
- p = self.escape_permalink(value)[0...self.permalink_options[:param_size]]
198
- p.ends_with?('-') ? p.chop : p
199
76
  end
200
77
  end
201
78
 
@@ -203,6 +80,18 @@ finder.
203
80
  end
204
81
  end
205
82
 
206
- if defined?(ActiveRecord)
207
- Railslove::Plugins::FindByParam.enable
83
+ class ActiveRecord::Base
84
+ class_attribute :permalink_options
85
+ self.permalink_options = {:param => :id}
86
+
87
+ #default finders these are overwritten if you use make_permalink in your model
88
+ def self.find_by_param(value,args={})
89
+ find_by_id(value,args)
90
+ end
91
+ def self.find_by_param!(value,args={})
92
+ find(value,args)
93
+ end
94
+
208
95
  end
96
+ ActiveRecord::Base.send(:include, Railslove::Plugins::FindByParam)
97
+
@@ -1,7 +1,7 @@
1
1
  module Railslove
2
2
  module Plugins
3
3
  module FindByParam
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.1'
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rd_find_by_param
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Bumann
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-03-16 00:00:00 -04:00
19
+ date: 2011-03-25 00:00:00 -04:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency