-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for automatic initialization using :initialize_with.
Changed the public method name to simply be #find_param. Refactored to remove dependence on class inheritable attributes. Improved the documentation.
- Loading branch information
Tyler Hunt
committed
May 29, 2008
1 parent
5d01367
commit 085b4bc
Showing
5 changed files
with
143 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,54 @@ | ||
This is a silly plugin to let you take a shortcut. Here's the blog post example: | ||
Find-Param | ||
========== | ||
|
||
class Post < ActiveRecord::Base | ||
define_find_param :slug | ||
end | ||
This is a simple plugin to let you easily define a parameter to use for | ||
#to_param, and also define a finder to access that same parameter. | ||
|
||
This will set the to_param to be post.slug and add the following method to the Post model: | ||
This plugin is most useful for situations where you want to override the usage | ||
of ID as the default parameter value. Using a slug creates URLs that can be | ||
friendlier for humans and bots alike. | ||
|
||
def self.find_by_param(*args) | ||
find_by_slug(*args) | ||
end | ||
|
||
You can also pass :raise_on_not_found => true to have it raise ActiveRecord::RecordNotFound | ||
if the result set is empty. | ||
Getting Started | ||
--------------- | ||
|
||
Like I said, it's silly, but I find myself using this pattern a lot. | ||
Here we define the find param to be a slug: | ||
|
||
class Post < ActiveRecord::Base | ||
find_param :slug | ||
end | ||
|
||
This will set the #to_param to be #slug and add a finder to the model called | ||
#find_by_param that can be used in your controllers to fetch records using | ||
params[:id]. | ||
|
||
class PostController | ||
before_filter :find_post, :only => %(show edit update destroy) | ||
|
||
def find_post | ||
find_by_param(params[:id]) | ||
end | ||
end | ||
|
||
|
||
Options | ||
------- | ||
|
||
To have your find param automatically populated on record creation, use the | ||
:initialize_with option. | ||
|
||
class Post < ActiveRecord::Base | ||
find_param :slug, :initialize_with => :title | ||
end | ||
|
||
This will use the title property to populate the slug. By default this value is | ||
lowercased and all whitespace and special characters are replaced by hyphens. | ||
To specify your own formatted for the find param, there a :using option that | ||
accepts a proc. | ||
|
||
class Post < ActiveRecord::Base | ||
find_param :slug, :initialize_with => :title, :using => Proc.new { |value| value.upcase } | ||
end | ||
|
||
You can also pass :raise_on_not_found => true to have it raise an | ||
ActiveRecord::RecordNotFound erorr when the result set is empty. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
require 'find_by_param' | ||
ActiveRecord::Base.send(:extend, FindByParam::ClassMethods) | ||
|
||
ActiveRecord::Base.send(:extend, FindByParam::ClassMethods) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,52 @@ | ||
module FindByParam | ||
|
||
## | ||
# Catch-all error for any issue arrising within the FindByParam plugin. | ||
# | ||
class Error < RuntimeError; end | ||
|
||
## | ||
# Raised when the param requested is not in the model's table definition. | ||
# For example: | ||
# | ||
# class WillRaiseError < ActiveRecord::Base | ||
# define_find_param :undefined_column | ||
# end | ||
|
||
# Raised when the param requested is not in the model's table definition: | ||
# | ||
# class WillRaiseError < ActiveRecord::Base | ||
# define_find_param :undefined_column | ||
# end | ||
class ColumnNotFoundError < Error; end | ||
|
||
module ClassMethods | ||
def define_find_param(param, options={}) | ||
param = param.to_s | ||
options[:raise_on_not_found] ||= false | ||
if column_names.include?(param) | ||
write_inheritable_attribute :find_parameter, param | ||
write_inheritable_attribute :find_param_options, options | ||
bl = lambda do |args| | ||
results = send("find_by_#{read_inheritable_attribute(:find_parameter)}", *args) | ||
raise ActiveRecord::RecordNotFound if options[:raise_on_not_found] && (results.nil? or (results.is_a?(Array) && results.size == 0)) | ||
return results | ||
# Defines a finder (#find_by_param) using the specified parameter name. | ||
# Also, defines #to_param to use the same parameter. | ||
# | ||
# Options: | ||
# * <tt>:raise_on_not_found</tt>: cases ActiveRecord::RecordNotFound to be raised when no record is found | ||
# * <tt>:initialize_with</tt>: the name of parameter to use to initialize the find parameter when a new record is created | ||
# * <tt>:using</tt>: a proc used to manipulated the initialization parameter before setting the find parameter | ||
def find_param(param, options={}) | ||
raise_on_not_found = options.delete(:raise_on_not_found) | ||
initialize_with = options.delete(:initialize_with) | ||
raise ColumnNotFoundError unless column_names.include?(param.to_s) | ||
|
||
self.class.send(:define_method, :find_by_param) do |args| | ||
returning send("find_by_#{param}", *args) do |results| | ||
raise ActiveRecord::RecordNotFound if raise_on_not_found && (results.nil? || (results.is_a?(Array) && results.size == 0)) | ||
end | ||
self.class.send(:define_method, 'find_by_param', &bl) | ||
else | ||
raise ColumnNotFoundError | ||
end | ||
self.send(:include, FindByParam::InstanceMethods) | ||
|
||
self.send(:alias_method, :to_param, param) | ||
|
||
initialize_parameter(param, initialize_with, options) if initialize_with | ||
end | ||
end | ||
|
||
module InstanceMethods | ||
def to_param | ||
self.send(self.class.read_inheritable_attribute(:find_parameter)) | ||
|
||
def initialize_parameter(param, source, options={}) | ||
raise ColumnNotFoundError unless column_names.include?(source.to_s) | ||
using = options.delete(:using) | ||
|
||
self.send(:define_method, :set_param) do | ||
value = self.send(source) | ||
value = using.respond_to?(:call) ? using.call(value) : value.downcase.gsub(/[^\w]+/, '-') | ||
|
||
self.send("#{param}=", value) | ||
end | ||
self.send(:private, :set_param) | ||
|
||
self.send(:before_create, :set_param) | ||
end | ||
private :initialize_parameter | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters