friendly_id 3.0.6 → 3.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.md CHANGED
@@ -6,6 +6,16 @@ suggestions, ideas and improvements to FriendlyId.
6
6
  * Table of Contents
7
7
  {:toc}
8
8
 
9
+ ## 3.1.0 (NOT RELEASED)
10
+
11
+ * Refactored/simplified Active Record 2 and 3 query code.
12
+ * Better support for Active Record 3 finds and scopes.
13
+ * Extract slug handling code into separate gem, [Babosa](http://github.com/norman/babosa).
14
+ * :max-length option now uses bytes rather than characters.
15
+ * Fix quoting issue that prevented using a domain- or database-qualified column. (thanks James Cropcho)
16
+ * Support for Active Record 2.2.x dropped; 2.3 or above is now required.
17
+ * Fixed a few small errors on Postgres.
18
+
9
19
  ## 3.0.6 (2010-06-10)
10
20
 
11
21
  * Fix bad call to apply_mapping on 2.3.
data/Contributors.md CHANGED
@@ -18,6 +18,7 @@ community, in particular from the following people:
18
18
  * Florian Aßmanqn
19
19
  * Harry Love
20
20
  * Ian Stewart
21
+ * James Cropcho
21
22
  * Jesse Crouch
22
23
  * Joe Van Dyk
23
24
  * Johan Kok
data/Guide.md CHANGED
@@ -131,9 +131,9 @@ for {FriendlyId::Configuration}.
131
131
 
132
132
  ## FriendlyId Strings
133
133
 
134
- FriendlyId comes with {FriendlyId::SlugString excellent support for Unicode
135
- strings}. When using slugs, FriendlyId will automatically modify the slug text
136
- to make it more suitable for use in a URL:
134
+ FriendlyId uses the [Babosa](http://github.com/norman/babosa) library for
135
+ generating slug strings. When using slugs, FriendlyId/Babosa will automatically
136
+ modify the slug text to make it more suitable for use in a URL:
137
137
 
138
138
  class City < ActiveRecord::Base
139
139
  has_friendly_id :name, :use_slug => true
@@ -180,15 +180,9 @@ There are special options for some languages:
180
180
  @post.create(:title => "¡Feliz año!")
181
181
  @post.title # will be "feliz-anno"
182
182
 
183
- ### Approximations for Other Languages
184
-
185
- You can add custom approximations for your language by adding Hash of
186
- approximations to {FriendlyId::SlugString::APPROXIMATIONS}. The approximations
187
- must be listed as Unicode decimal numbers, and arrays of numbers.
188
-
189
183
  ### Unicode Slugs
190
184
 
191
- By default, any character outside the Unicode Western character sets will be
185
+ By default, any character outside the Unicode Latin character range will be
192
186
  passed through untouched, allowing you to have slugs in Arabic, Japanese,
193
187
  Greek, etc:
194
188
 
@@ -514,15 +508,6 @@ Before removing any public or protected methods, FriendlyId will deprecate
514
508
  them through one major release cycle. Private methods may, however, change at
515
509
  any time.
516
510
 
517
- ## Running the Tests
518
-
519
- FriendlyId uses [Bundler](http://github.com/carlhuda/bundler) to manage its gem
520
- dependencies. To run the tests, first make sure you have bundler installed.
521
- Then, copy Gemfile.default to Gemfile. If you wish to test against different gem
522
- versions than the ones specified in the Gemfile (for example, to test with
523
- Postgres or MySQL rather than SQLite3, or to test against different versions of
524
- ActiveRecord), then simply modify the Gemfile to suit your dependencies.
525
-
526
511
  ## Some Benchmarks
527
512
 
528
513
  These benchmarks can give you an idea of FriendlyId's impact on the
@@ -535,27 +520,31 @@ decide not to use FriendlyId for performance reasons, keep in mind that your
535
520
  own solution is unlikely to be any faster than FriendlyId with cached slugs
536
521
  enabled. But if it is, then your patches would be very welcome!
537
522
 
538
- ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.2.0]
539
- activerecord (2.3.5)
540
- friendly_id (2.3.2)
541
- sqlite3 3.6.19 in-memory database
523
+
524
+ activerecord (2.3.8)
525
+ ruby 1.9.2dev (2010-07-06 revision 28549) [x86_64-darwin10.4.0]
526
+ friendly_id (3.1.0)
527
+ sqlite3 3.6.12 in-memory database
528
+
542
529
  | DEFAULT | NO_SLUG | SLUG | CACHED_SLUG |
543
530
  ------------------------------------------------------------------------------------------------
544
- find model by id x1000 | 0.274 | 0.426 | 0.780 | 0.489 |
545
- find model using array of ids x1000 | 0.517 | 0.525 | 1.692 | 0.623 |
546
- find model using id, then to_param x1000 | 0.279 | 0.431 | 1.253 | 0.498 |
531
+ find model by id x1000 | 0.340 | 0.468 | 0.877 | 0.534 |
532
+ find model using array of ids x1000 | 0.551 | 0.592 | 0.989 | 0.893 |
533
+ find model using id, then to_param x1000 | 0.340 | 0.487 | 1.310 | 0.551 |
547
534
  ================================================================================================
548
- Total | 1.071 | 1.382 | 3.725 | 1.610 |
535
+ Total | 1.231 | 1.547 | 3.176 | 1.979 |
536
+
537
+
549
538
 
550
- ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.2.0]
551
- activerecord (3.0.0.beta1)
552
- friendly_id (2.3.2)
553
- sqlite3 3.6.19 in-memory database
539
+ activerecord (3.0.0.beta4)
540
+ ruby 1.9.2dev (2010-07-06 revision 28549) [x86_64-darwin10.4.0]
541
+ friendly_id (3.1.0)
542
+ sqlite3 3.6.12 in-memory database
554
543
 
555
544
  | DEFAULT | NO_SLUG | SLUG | CACHED_SLUG |
556
545
  ------------------------------------------------------------------------------------------------
557
- find model by id x1000 | 0.557 | 1.135 | 6.491 | 1.398 |
558
- find model using array of ids x1000 | 0.862 | 0.882 | 6.152 | 1.919 |
559
- find model using id, then to_param x1000 | 0.658 | 2.200 | 8.398 | 1.539 |
546
+ find model by id x1000 | 0.495 | 0.608 | 1.519 | 0.641 |
547
+ find model using array of ids x1000 | 0.708 | 0.722 | 6.483 | 0.782 |
548
+ find model using id, then to_param x1000 | 0.506 | 0.645 | 2.644 | 0.637 |
560
549
  ================================================================================================
561
- Total | 2.077 | 4.217 | 21.041 | 4.856 |
550
+ Total | 1.709 | 1.976 | 10.645 | 2.061 |
data/README.md CHANGED
@@ -19,7 +19,7 @@ versioning, scoped slugs, reserved words, custom slug generators, and
19
19
  excellent Unicode support. For complete information on using FriendlyId,
20
20
  please see the {http://norman.github.com/friendly_id/file.Guide.html FriendlyId Guide}.
21
21
 
22
- FriendlyId is compatible with Rails 2.2.x - 3.0.
22
+ FriendlyId is compatible with Rails 2.3.x and 3.0.
23
23
 
24
24
  ## Rails Quickstart
25
25
 
@@ -30,7 +30,7 @@ FriendlyId is compatible with Rails 2.2.x - 3.0.
30
30
  cd my_app
31
31
 
32
32
  # add to Gemfile
33
- gem "friendly_id", "~> 3.0"
33
+ gem "friendly_id", "~> 3.1"
34
34
 
35
35
  rails generate friendly_id
36
36
  rails generate scaffold user name:string cached_slug:string
@@ -63,8 +63,8 @@ for this project.
63
63
 
64
64
  If you have a bug to report, please include the following information:
65
65
 
66
+ * **Version information for FriendlyId, Rails and Ruby.**
66
67
  * Stack trace and error message.
67
- * Version information for FriendlyId, Rails and Ruby.
68
68
  * Any snippets of relevant model, view or controller code that shows how your
69
69
  are using FriendlyId.
70
70
 
data/Rakefile CHANGED
@@ -1,17 +1,12 @@
1
1
  require "rake"
2
2
  require "rake/testtask"
3
3
  require "rake/gempackagetask"
4
- require "rake/rdoctask"
5
4
  require "rake/clean"
6
5
 
7
6
  task :default => :test
8
7
 
9
8
  CLEAN << "pkg" << "doc" << "coverage" << ".yardoc"
10
9
  Rake::GemPackageTask.new(eval(File.read("friendly_id.gemspec"))) { |pkg| }
11
- Rake::RDocTask.new do |r|
12
- r.rdoc_dir = "doc"
13
- r.rdoc_files.include "lib/**/*.rb"
14
- end
15
10
 
16
11
  begin
17
12
  require "yard"
data/extras/bench.rb CHANGED
@@ -1,4 +1,8 @@
1
- require File.expand_path('../extras', __FILE__)
1
+ $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+ $:.unshift File.expand_path(File.dirname(__FILE__))
3
+ $:.uniq!
4
+
5
+ require "extras"
2
6
  require 'rbench'
3
7
  FACTOR = 10
4
8
 
data/extras/prof.rb CHANGED
@@ -1,5 +1,8 @@
1
- #!/usr/bin/env ruby -KU
2
- require File.dirname(__FILE__) + '/extras'
1
+ $:.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+ $:.unshift File.expand_path(File.dirname(__FILE__))
3
+ $:.uniq!
4
+
5
+ require "extras"
3
6
  require 'ruby-prof'
4
7
 
5
8
  # RubyProf.measure_mode = RubyProf::MEMORY
@@ -10,5 +13,7 @@ RubyProf.start
10
13
  end
11
14
  result = RubyProf.stop
12
15
  GC.enable
13
- printer = RubyProf::CallTreePrinter.new(result)
14
- printer.print(File.new("prof.txt", "w"))
16
+ # printer = RubyProf::CallTreePrinter.new(result)
17
+ printer = RubyProf::GraphPrinter.new(result)
18
+ version = ActiveRecord::VERSION::STRING.gsub(".", "")
19
+ printer.print(File.new("prof#{version}.txt", "w"))
data/lib/friendly_id.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "babosa"
1
2
  require "forwardable"
2
3
  require "active_support/core_ext/class/attribute_accessors"
3
4
  begin
@@ -7,11 +8,10 @@ rescue MissingSourceFile
7
8
  require "active_support/core_ext/blank"
8
9
  end
9
10
 
10
- require File.join(File.dirname(__FILE__), "friendly_id", "slug_string")
11
- require File.join(File.dirname(__FILE__), "friendly_id", "configuration")
12
- require File.join(File.dirname(__FILE__), "friendly_id", "status")
13
- require File.join(File.dirname(__FILE__), "friendly_id", "finders")
14
- require File.join(File.dirname(__FILE__), "friendly_id", "slugged")
11
+ require "friendly_id/slug_string"
12
+ require "friendly_id/configuration"
13
+ require "friendly_id/status"
14
+ require "friendly_id/slugged"
15
15
 
16
16
  # FriendlyId is a comprehensive Ruby library for slugging and permalinks with
17
17
  # ActiveRecord.
@@ -66,8 +66,36 @@ class String
66
66
  def parse_friendly_id(separator = nil)
67
67
  separator ||= FriendlyId::Configuration::DEFAULTS[:sequence_separator]
68
68
  name, sequence = split(/#{Regexp.escape(separator)}(\d+)?\z/)
69
- return name, sequence ||= "1"
69
+ return name, (sequence ||= 1).to_i
70
70
  end
71
71
  end
72
72
 
73
- require File.join(File.dirname(__FILE__), "friendly_id", "railtie") if defined?(Rails) && Rails.version >= "3"
73
+ class Object
74
+
75
+ # Is the object a friendly id? Note that the return value here is
76
+ # +false+ if the +id+ is definitely not friendly, and +nil+ if it can
77
+ # not be determined.
78
+ # The return value will be:
79
+ # * +true+ - if the id is definitely friendly (i.e., a string with non-numeric characters)
80
+ # * +false+ - if the id is definitely unfriendly (i.e., an Integer, a model instance, etc.)
81
+ # * +nil+ - if it can not be determined (i.e., a numeric string like "206".)
82
+ # @return [true, false, nil]
83
+ # @see #unfriendly?
84
+ def friendly_id?
85
+ if kind_of?(Integer) or kind_of?(Symbol) or self.class.respond_to? :friendly_id_config
86
+ false
87
+ elsif to_i.to_s != to_s
88
+ true
89
+ end
90
+ end
91
+
92
+ # Is the object a numeric id?
93
+ # @return [true, false, nil] +true+ if definitely unfriendly, +false+ if
94
+ # definitely friendly, else +nil+.
95
+ # @see #friendly?
96
+ def unfriendly_id?
97
+ val = friendly_id? ; !val unless val.nil?
98
+ end
99
+ end
100
+
101
+ require "friendly_id/railtie" if defined?(Rails) && Rails.version >= "3"
@@ -1,12 +1,11 @@
1
1
  module FriendlyId
2
2
 
3
- module ActiveRecordAdapter
3
+ # Are we running on ActiveRecord 3 or higher?
4
+ def self.on_ar3?
5
+ ActiveRecord::VERSION::STRING >= "3"
6
+ end
4
7
 
5
- module Compat
6
- def self.scope_method
7
- ActiveRecord::VERSION::STRING >= "3" ? :scope : :named_scope
8
- end
9
- end
8
+ module ActiveRecordAdapter
10
9
 
11
10
  include FriendlyId::Base
12
11
 
@@ -28,8 +27,8 @@ module FriendlyId
28
27
  # wish to use +attr_accessible+, you must invoke it BEFORE you invoke
29
28
  # {#has_friendly_id} in your class.
30
29
  def protect_friendly_id_attributes
31
- # only protect the column if the class is not already using attributes_accessible
32
- if !accessible_attributes
30
+ # only protect the column if the class is not already using attr_accessible
31
+ unless accessible_attributes.present?
33
32
  if friendly_id_config.custom_cache_column?
34
33
  attr_protected friendly_id_config.cache_column
35
34
  end
@@ -40,13 +39,29 @@ module FriendlyId
40
39
  end
41
40
  end
42
41
 
43
- class ActiveRecord::Base
44
- extend FriendlyId::ActiveRecordAdapter
45
- end
42
+ require "friendly_id/active_record_adapter/relation"
43
+ require "friendly_id/active_record_adapter/configuration"
44
+ require "friendly_id/active_record_adapter/finders"
45
+ require "friendly_id/active_record_adapter/simple_model"
46
+ require "friendly_id/active_record_adapter/slugged_model"
47
+ require "friendly_id/active_record_adapter/slug"
48
+ require "friendly_id/active_record_adapter/tasks"
46
49
 
47
- require File.join(File.dirname(__FILE__), "active_record_adapter", "configuration")
48
- require File.join(File.dirname(__FILE__), "active_record_adapter", "finders")
49
- require File.join(File.dirname(__FILE__), "active_record_adapter", "simple_model")
50
- require File.join(File.dirname(__FILE__), "active_record_adapter", "slugged_model")
51
- require File.join(File.dirname(__FILE__), "active_record_adapter", "slug")
52
- require File.join(File.dirname(__FILE__), "active_record_adapter", "tasks")
50
+ module ActiveRecord
51
+ class Base
52
+ extend FriendlyId::ActiveRecordAdapter
53
+ unless FriendlyId.on_ar3?
54
+ class << self
55
+ VALID_FIND_OPTIONS << :scope
56
+ end
57
+ end
58
+ end
59
+
60
+ if defined? Relation
61
+ class Relation
62
+ alias find_one_without_friendly find_one
63
+ alias find_some_without_friendly find_some
64
+ include FriendlyId::ActiveRecordAdapter::Relation
65
+ end
66
+ end
67
+ end
@@ -57,6 +57,7 @@ module FriendlyId
57
57
 
58
58
  def associated_friendly_classes
59
59
  configured_class.reflect_on_all_associations.select { |assoc|
60
+ assoc &&
60
61
  !assoc.options[:polymorphic] &&
61
62
  assoc.klass.uses_friendly_id?
62
63
  }.map(&:klass)
@@ -1,156 +1,162 @@
1
1
  module FriendlyId
2
-
3
- # The adapter for Ruby on Rails's ActiveRecord. Compatible with AR 2.2.x -
4
- # 2.3.x.
5
2
  module ActiveRecordAdapter
6
-
7
- # The classes in this module are used internally by FriendlyId, and exist
8
- # largely to avoid polluting the ActiveRecord models with too many
9
- # FriendlyId-specific methods.
10
3
  module Finders
11
4
 
12
- # FinderProxy is used to choose which finder class to instantiate;
13
- # depending on the model_class's +friendly_id_config+ and the options
14
- # passed into the constructor, it will decide whether to use simple or
15
- # slugged finder, a single or multiple finder, and in the case of slugs,
16
- # a cached or uncached finder.
17
- class FinderProxy
5
+ class Find
18
6
 
19
7
  extend Forwardable
8
+ def_delegators :@klass, :scoped, :friendly_id_config, :quoted_table_name, :table_name, :primary_key,
9
+ :connection, :name, :sanitize_sql
10
+ def_delegators :fc, :use_slugs?, :cache_column, :cache_column?
11
+ alias fc friendly_id_config
20
12
 
21
- attr_reader :finder
22
- attr :finder_class
23
- attr :ids
24
- attr :model_class
13
+ attr :klass
14
+ attr :id
25
15
  attr :options
26
-
27
- def_delegators :finder, :find, :unfriendly?
28
-
29
- def initialize(model_class, *args, &block)
30
- @model_class = model_class
31
- @ids = args.shift
32
- @options = args.first.kind_of?(Hash) ? args.first : {}
33
- end
34
-
35
- # Perform the find query.
36
- def finder
37
- @finder ||= finder_class.new(ids, model_class, options)
38
- end
39
-
40
- def finder_class
41
- @finder_class ||= slugged? ? slugged_finder_class : simple_finder_class
42
- end
43
-
44
- def multiple?
45
- ids.kind_of? Array
46
- end
47
-
48
- private
49
-
50
- def cache_available?
51
- !! model_class.friendly_id_config.cache_column
52
- end
53
-
54
- def multiple_slugged_finder_class
55
- use_cache? ? SluggedModel::CachedMultipleFinder : SluggedModel::MultipleFinder
56
- end
57
-
58
- def simple_finder_class
59
- multiple? ? SimpleModel::MultipleFinder : SimpleModel::SingleFinder
60
- end
61
-
62
- def slugged?
63
- !! model_class.friendly_id_config.use_slug?
64
- end
65
-
66
- def slugged_finder_class
67
- multiple? ? multiple_slugged_finder_class : single_slugged_finder_class
68
- end
69
-
70
- def scoped?
71
- !! options[:scope]
72
- end
73
-
74
- def single_slugged_finder_class
75
- use_cache? ? SluggedModel::CachedSingleFinder : SluggedModel::SingleFinder
76
- end
77
-
78
- def use_cache?
79
- cache_available? and !scoped?
80
- end
81
-
82
- end
83
-
84
- # Wraps finds for multiple records using an array of friendly_ids.
85
- # @abstract
86
- module Multiple
87
-
88
- include FriendlyId::Finders::Base
89
-
90
- attr_reader :friendly_ids, :results, :unfriendly_ids
91
-
92
- def initialize(ids, model_class, options={})
93
- @friendly_ids, @unfriendly_ids = ids.partition {|id| FriendlyId::Finders::Base.friendly?(id) }
94
- @unfriendly_ids = @unfriendly_ids.map {|id| id.class.respond_to?(:friendly_id_config) ? id.id : id}
95
- super
16
+ attr :scope_val
17
+ attr :result
18
+ attr :friendly_ids
19
+ attr :unfriendly_ids
20
+
21
+ def initialize(klass, id, options)
22
+ @klass = klass
23
+ @id = id
24
+ @options = options
25
+ @scope_val = options.delete(:scope)
26
+ @scope_val = @scope_val.to_param if @scope_val && @scope_val.respond_to?(:to_param)
27
+ end
28
+
29
+ def find_one
30
+ return find_one_using_cached_slug if cache_column?
31
+ return find_one_using_slug if use_slugs?
32
+ @result = scoped(:conditions => ["#{table_name}.#{fc.column} = ?", id]).first(options)
33
+ assign_status
34
+ end
35
+
36
+ def find_some
37
+ parse_ids!
38
+ scope = some_friendly_scope
39
+ if use_slugs? && @friendly_ids.present?
40
+ scope = scope.scoped(:joins => Slug.table_name.to_sym)
41
+ if fc.scope?
42
+ scope = scope.scoped(:conditions => {:slugs => {:scope => scope_val}})
43
+ end
44
+ end
45
+ @result = scope.all(options).uniq
46
+ validate_expected_size!
47
+ @result.each { |record| record.friendly_id_status.name = id }
48
+ end
49
+
50
+ def raise_error(error)
51
+ raise(error) unless fc.scope?
52
+ scope_message = scope_val || "expected, but none given"
53
+ message = "%s, scope: %s" % [error.message, scope_message]
54
+ raise ActiveRecord::RecordNotFound, message
96
55
  end
97
56
 
98
57
  private
99
58
 
100
- # An error message to use when the wrong number of results was returned.
101
- def error_message
102
- "Couldn't find all %s with IDs (%s) AND %s (found %d results, but was looking for %d)" % [
103
- model_class.name.pluralize,
104
- ids.join(', '),
59
+ def find_one_using_cached_slug
60
+ @result = scoped(:conditions => ["#{table_name}.#{cache_column} = ?", id]).first(options)
61
+ assign_status or find_one_using_slug
62
+ end
63
+
64
+ def find_one_using_slug
65
+ name, seq = id.to_s.parse_friendly_id
66
+ slugs = Slug.table_name.to_sym
67
+ scope = scoped(:conditions => {slugs => {:name => name, :sequence => seq}}, :joins => slugs)
68
+ scope = scope.scoped(:conditions => {slugs => {:scope => scope_val}}) if fc.scope?
69
+ @result = scope.first(options)
70
+ assign_status
71
+ end
72
+
73
+ def parse_ids!
74
+ @id = id.uniq.map do |member|
75
+ if member.respond_to?(:friendly_id_config)
76
+ member.id.to_i
77
+ else
78
+ member
79
+ end
80
+ end
81
+ @friendly_ids, @unfriendly_ids = @id.partition {|member| member.friendly_id?}
82
+ end
83
+
84
+ def validate_expected_size!
85
+ expected = expected_size
86
+ return if @result.size == expected
87
+ message = "Couldn't find all %s with IDs (%s) AND %s (found %d results, but was looking for %d)" % [
88
+ name.pluralize,
89
+ id.join(', '),
105
90
  sanitize_sql(options[:conditions]),
106
- results.size,
107
- expected_size
91
+ result.size,
92
+ expected
108
93
  ]
94
+ raise ActiveRecord::RecordNotFound, message
109
95
  end
110
96
 
111
- # How many results do we expect?
112
- def expected_size
113
- limited? ? limit : offset_size
114
- end
115
-
116
- # The limit option passed to the find.
117
- def limit
118
- options[:limit]
97
+ def assign_status
98
+ return unless @result
99
+ name, seq = @id.to_s.parse_friendly_id
100
+ @result.friendly_id_status.name = name
101
+ @result.friendly_id_status.sequence = seq if use_slugs?
102
+ @result
119
103
  end
120
104
 
121
- # Is the find limited?
122
- def limited?
123
- offset_size > limit if limit
124
- end
125
-
126
- # The offset used for the find. If no offset was passed, 0 is returned.
127
- def offset
128
- options[:offset].to_i
129
- end
130
-
131
- # The number of ids, minus the offset.
132
- def offset_size
133
- ids.size - offset
105
+ def expected_size
106
+ if options[:limit] && @id.size > options[:limit]
107
+ options[:limit]
108
+ else
109
+ @id.size
110
+ end
111
+ end
112
+
113
+ def some_friendly_scope
114
+ query_slugs = use_slugs? && !cache_column?
115
+ pkey = "#{quoted_table_name}.#{primary_key}"
116
+ column = "#{table_name}.#{cache_column || fc.column}"
117
+ if @unfriendly_ids.present?
118
+ conditions = ["#{pkey} IN (?)", @unfriendly_ids]
119
+ if @friendly_ids.present?
120
+ if query_slugs
121
+ conditions[0] << " OR #{some_slugged_conditions}"
122
+ else
123
+ conditions[0] << " OR #{column} IN (?)"
124
+ conditions << @friendly_ids
125
+ end
126
+ end
127
+ elsif @friendly_ids.present?
128
+ conditions = query_slugs ? some_slugged_conditions : ["#{column} IN (?)", @friendly_ids]
129
+ end
130
+ scoped(:conditions => conditions)
131
+ end
132
+
133
+ def some_slugged_conditions
134
+ return unless @friendly_ids.present?
135
+ slug_table = Slug.quoted_table_name
136
+ fragment = "(#{slug_table}.name = %s AND #{slug_table}.sequence = %d)"
137
+ @friendly_ids.inject(nil) do |clause, id|
138
+ name, seq = id.parse_friendly_id
139
+ string = fragment % [connection.quote(name), seq]
140
+ clause ? clause + " OR #{string}" : string
141
+ end
134
142
  end
135
-
136
143
  end
137
144
 
138
- end
139
-
140
- # The methods in this module override ActiveRecord's +find_one+ and
141
- # +find_some+ to add FriendlyId's features.
142
- module FinderMethods
143
-
144
- def find(*args, &block)
145
- finder = Finders::FinderProxy.new(self, *args, &block)
146
- if finder.multiple?
147
- finder.find
148
- else
149
- finder.unfriendly? ? super : finder.find or super
150
- end
145
+ def find_one(id, options)
146
+ return super if id.blank? || id.unfriendly_id?
147
+ finder = Find.new(self, id, options)
148
+ finder.find_one or super
149
+ rescue ActiveRecord::RecordNotFound => error
150
+ finder.raise_error(error)
151
151
  end
152
152
 
153
+ def find_some(ids, options)
154
+ return super if ids.empty?
155
+ finder = Find.new(self, ids, options)
156
+ finder.find_some
157
+ rescue ActiveRecord::RecordNotFound => error
158
+ finder.raise_error(error)
159
+ end
153
160
  end
154
-
155
161
  end
156
162
  end