rd_find_by_param 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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