rd_find_by_param 0.1.0
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.
- data/lib/find_by_param.rb +208 -0
- data/lib/find_by_param/version.rb +7 -0
- metadata +126 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
begin
|
2
|
+
$KCODE = 'u'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'active_support'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
module Railslove
|
9
|
+
module Plugins
|
10
|
+
module FindByParam
|
11
|
+
def self.enable # :nodoc:
|
12
|
+
return if ActiveRecord::Base.kind_of?(self::ClassMethods)
|
13
|
+
|
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)
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
|
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
|
+
def make_permalink(options={})
|
60
|
+
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
|
+
|
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
|
79
|
+
|
80
|
+
if self.column_names.include?(options[:field].to_s)
|
81
|
+
options[:param] = options[:field]
|
82
|
+
before_save :save_permalink
|
83
|
+
end
|
84
|
+
|
85
|
+
self.permalink_options = options
|
86
|
+
extend Railslove::Plugins::FindByParam::SingletonMethods
|
87
|
+
include Railslove::Plugins::FindByParam::InstanceMethods
|
88
|
+
rescue ActiveRecord::ActiveRecordError
|
89
|
+
puts "[find_by_param error] database not available?"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module SingletonMethods
|
94
|
+
|
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={})
|
102
|
+
if permalink_options[:prepend_id]
|
103
|
+
param = "id"
|
104
|
+
value = value.to_i
|
105
|
+
else
|
106
|
+
param = permalink_options[:param]
|
107
|
+
end
|
108
|
+
self.send("find_by_#{param}".to_sym, value, args)
|
109
|
+
end
|
110
|
+
|
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
|
+
def find_by_param!(value, args={})
|
120
|
+
param = permalink_options[:param]
|
121
|
+
obj = find_by_param(value, args)
|
122
|
+
raise ::ActiveRecord::RecordNotFound unless obj
|
123
|
+
obj
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
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
|
+
|
140
|
+
protected
|
141
|
+
|
142
|
+
def save_permalink
|
143
|
+
return unless self.class.column_names.include?(permalink_options[:field].to_s)
|
144
|
+
counter = 0
|
145
|
+
base_value = escape_and_truncate_permalink(send(permalink_options[:with])).downcase
|
146
|
+
permalink_value = base_value.to_s
|
147
|
+
|
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
|
155
|
+
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
|
163
|
+
|
164
|
+
conditions[1] = permalink_value
|
165
|
+
end
|
166
|
+
write_attribute(permalink_options[:field], permalink_value)
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
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
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
if defined?(ActiveRecord)
|
207
|
+
Railslove::Plugins::FindByParam.enable
|
208
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rd_find_by_param
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Michael Bumann
|
14
|
+
- Gregor Schmidt
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-03-16 00:00:00 -04:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: activerecord
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
version: "3.0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activesupport
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 7
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 0
|
49
|
+
version: "3.0"
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: sqlite3-ruby
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rake
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
description: find_by_param is a nice and easy way to handle permalinks and dealing with searching for to_param values
|
81
|
+
email: sean@railsdog.com
|
82
|
+
executables: []
|
83
|
+
|
84
|
+
extensions: []
|
85
|
+
|
86
|
+
extra_rdoc_files: []
|
87
|
+
|
88
|
+
files:
|
89
|
+
- lib/find_by_param/version.rb
|
90
|
+
- lib/find_by_param.rb
|
91
|
+
has_rdoc: true
|
92
|
+
homepage: http://github.com/railsdog/find_by_param
|
93
|
+
licenses: []
|
94
|
+
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 3
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 3
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
requirements: []
|
119
|
+
|
120
|
+
rubyforge_project: "[none]"
|
121
|
+
rubygems_version: 1.3.7
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: Rails plugin to handle permalink values
|
125
|
+
test_files: []
|
126
|
+
|