Skip to content
Browse files

Add AR::Base.to_param for convenient "pretty" URLs derived from a mod…

…el's attribute or method.
  • Loading branch information...
1 parent 0542767 commit 547999df256a5ac650eb012dabf713027b9bda1f @javan javan committed Nov 14, 2013
View
14 activerecord/CHANGELOG.md
@@ -1,3 +1,17 @@
+* Added `ActiveRecord::Base.to_param` for convenient "pretty" URLs derived from a model's attribute or method.
+
+ Example:
+
+ class User < ActiveRecord::Base
+ to_param :name
+ end
+
+ user = User.find_by(name: 'Fancy Pants')
+ user.id # => 123
+ user.to_param # => "123-fancy-pants"
+
+ *Javan Makhmali*
+
* Added `ActiveRecord::Base.no_touching`, which allows ignoring touch on models.
Examples:
View
31 activerecord/lib/active_record/integration.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
module Integration
extend ActiveSupport::Concern
@@ -65,5 +67,34 @@ def cache_key(*timestamp_names)
"#{self.class.model_name.cache_key}/#{id}"
end
end
+
+ module ClassMethods
+ # Defines your model's +to_param+ method to generate "pretty" URLs
+ # using +method_name+, which can be any attribute or method that
+ # responds to +to_s+.
+ #
+ # class User < ActiveRecord::Base
+ # to_param :name
+ # end
+ #
+ # user = User.find_by(name: 'Fancy Pants')
+ # user.id # => 123
+ # user_path(user) # => "/users/123-fancy-pants"
+ #
+ # Because the generated param begins with the record's +id+, it is
+ # suitable for passing to +find+. In a controller, for example:
+ #
+ # params[:id] # => "123-fancy-pants"
+ # User.find(params[:id]).id # => 123
+ def to_param(method_name)
+ define_method :to_param do
+ if (default = super()) && (result = send(method_name).to_s).present?
+ "#{default}-#{result.truncate(20, separator: /\s/, omission: nil).parameterize}"
+ else
+ default
+ end
+ end
+ end
+ end
end
end
View
18 activerecord/test/cases/integration_test.rb
@@ -23,6 +23,24 @@ def test_to_param_returns_id_if_not_persisted_but_id_is_set
assert_equal '1', client.to_param
end
+ def test_to_param_class_method
+ firm = Firm.find(4)
+ assert_equal '4-flamboyant-software', firm.to_param
+ end
+
+ def to_param_class_method_uses_default_if_blank
+ firm = Firm.find(4)
+ firm.name = nil
+ assert_equal '4', firm.to_param
+ firm.name = ' '
+ assert_equal '4', firm.to_param
+ end
+
+ def to_param_class_method_uses_default_if_not_persisted
+ firm = Firm.new(name: 'Fancy Shirts')
+ assert_equal nil, firm.to_param
+ end
+
def test_cache_key_for_existing_record_is_not_timezone_dependent
utc_key = Developer.first.cache_key
View
2 activerecord/test/models/company.rb
@@ -40,6 +40,8 @@ class Client < ::Company
end
class Firm < Company
+ to_param :name
+
has_many :clients, -> { order "id" }, :dependent => :destroy, :before_remove => :log_before_remove, :after_remove => :log_after_remove
has_many :unsorted_clients, :class_name => "Client"
has_many :unsorted_clients_with_symbol, :class_name => :Client

0 comments on commit 547999d

Please sign in to comment.
Something went wrong with that request. Please try again.