sskirby-activerecord 3.2.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.
Files changed (150) hide show
  1. data/CHANGELOG.md +6749 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +222 -0
  4. data/examples/associations.png +0 -0
  5. data/examples/performance.rb +177 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record.rb +147 -0
  8. data/lib/active_record/aggregations.rb +255 -0
  9. data/lib/active_record/associations.rb +1604 -0
  10. data/lib/active_record/associations/alias_tracker.rb +79 -0
  11. data/lib/active_record/associations/association.rb +239 -0
  12. data/lib/active_record/associations/association_scope.rb +119 -0
  13. data/lib/active_record/associations/belongs_to_association.rb +79 -0
  14. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +34 -0
  15. data/lib/active_record/associations/builder/association.rb +55 -0
  16. data/lib/active_record/associations/builder/belongs_to.rb +85 -0
  17. data/lib/active_record/associations/builder/collection_association.rb +75 -0
  18. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -0
  19. data/lib/active_record/associations/builder/has_many.rb +71 -0
  20. data/lib/active_record/associations/builder/has_one.rb +62 -0
  21. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  22. data/lib/active_record/associations/collection_association.rb +574 -0
  23. data/lib/active_record/associations/collection_proxy.rb +132 -0
  24. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +62 -0
  25. data/lib/active_record/associations/has_many_association.rb +108 -0
  26. data/lib/active_record/associations/has_many_through_association.rb +180 -0
  27. data/lib/active_record/associations/has_one_association.rb +73 -0
  28. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  29. data/lib/active_record/associations/join_dependency.rb +214 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +154 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  33. data/lib/active_record/associations/join_helper.rb +55 -0
  34. data/lib/active_record/associations/preloader.rb +177 -0
  35. data/lib/active_record/associations/preloader/association.rb +127 -0
  36. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  37. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  38. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  39. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  40. data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
  41. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  42. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  43. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  44. data/lib/active_record/associations/preloader/through_association.rb +67 -0
  45. data/lib/active_record/associations/singular_association.rb +64 -0
  46. data/lib/active_record/associations/through_association.rb +83 -0
  47. data/lib/active_record/attribute_assignment.rb +221 -0
  48. data/lib/active_record/attribute_methods.rb +272 -0
  49. data/lib/active_record/attribute_methods/before_type_cast.rb +31 -0
  50. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  51. data/lib/active_record/attribute_methods/dirty.rb +101 -0
  52. data/lib/active_record/attribute_methods/primary_key.rb +114 -0
  53. data/lib/active_record/attribute_methods/query.rb +39 -0
  54. data/lib/active_record/attribute_methods/read.rb +135 -0
  55. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  56. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -0
  57. data/lib/active_record/attribute_methods/write.rb +69 -0
  58. data/lib/active_record/autosave_association.rb +422 -0
  59. data/lib/active_record/base.rb +716 -0
  60. data/lib/active_record/callbacks.rb +275 -0
  61. data/lib/active_record/coders/yaml_column.rb +41 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +188 -0
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +58 -0
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +388 -0
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -0
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +115 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +492 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +598 -0
  70. data/lib/active_record/connection_adapters/abstract_adapter.rb +296 -0
  71. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  72. data/lib/active_record/connection_adapters/column.rb +270 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +288 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +426 -0
  75. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1261 -0
  76. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +55 -0
  78. data/lib/active_record/connection_adapters/sqlite_adapter.rb +577 -0
  79. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  80. data/lib/active_record/counter_cache.rb +119 -0
  81. data/lib/active_record/dynamic_finder_match.rb +56 -0
  82. data/lib/active_record/dynamic_matchers.rb +79 -0
  83. data/lib/active_record/dynamic_scope_match.rb +23 -0
  84. data/lib/active_record/errors.rb +195 -0
  85. data/lib/active_record/explain.rb +85 -0
  86. data/lib/active_record/explain_subscriber.rb +21 -0
  87. data/lib/active_record/fixtures.rb +906 -0
  88. data/lib/active_record/fixtures/file.rb +65 -0
  89. data/lib/active_record/identity_map.rb +156 -0
  90. data/lib/active_record/inheritance.rb +167 -0
  91. data/lib/active_record/integration.rb +49 -0
  92. data/lib/active_record/locale/en.yml +40 -0
  93. data/lib/active_record/locking/optimistic.rb +183 -0
  94. data/lib/active_record/locking/pessimistic.rb +77 -0
  95. data/lib/active_record/log_subscriber.rb +68 -0
  96. data/lib/active_record/migration.rb +765 -0
  97. data/lib/active_record/migration/command_recorder.rb +105 -0
  98. data/lib/active_record/model_schema.rb +366 -0
  99. data/lib/active_record/nested_attributes.rb +469 -0
  100. data/lib/active_record/observer.rb +121 -0
  101. data/lib/active_record/persistence.rb +372 -0
  102. data/lib/active_record/query_cache.rb +74 -0
  103. data/lib/active_record/querying.rb +58 -0
  104. data/lib/active_record/railtie.rb +119 -0
  105. data/lib/active_record/railties/console_sandbox.rb +6 -0
  106. data/lib/active_record/railties/controller_runtime.rb +49 -0
  107. data/lib/active_record/railties/databases.rake +620 -0
  108. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  109. data/lib/active_record/readonly_attributes.rb +26 -0
  110. data/lib/active_record/reflection.rb +534 -0
  111. data/lib/active_record/relation.rb +534 -0
  112. data/lib/active_record/relation/batches.rb +90 -0
  113. data/lib/active_record/relation/calculations.rb +354 -0
  114. data/lib/active_record/relation/delegation.rb +49 -0
  115. data/lib/active_record/relation/finder_methods.rb +398 -0
  116. data/lib/active_record/relation/predicate_builder.rb +58 -0
  117. data/lib/active_record/relation/query_methods.rb +417 -0
  118. data/lib/active_record/relation/spawn_methods.rb +148 -0
  119. data/lib/active_record/result.rb +34 -0
  120. data/lib/active_record/sanitization.rb +194 -0
  121. data/lib/active_record/schema.rb +58 -0
  122. data/lib/active_record/schema_dumper.rb +204 -0
  123. data/lib/active_record/scoping.rb +152 -0
  124. data/lib/active_record/scoping/default.rb +142 -0
  125. data/lib/active_record/scoping/named.rb +202 -0
  126. data/lib/active_record/serialization.rb +18 -0
  127. data/lib/active_record/serializers/xml_serializer.rb +202 -0
  128. data/lib/active_record/session_store.rb +358 -0
  129. data/lib/active_record/store.rb +50 -0
  130. data/lib/active_record/test_case.rb +73 -0
  131. data/lib/active_record/timestamp.rb +113 -0
  132. data/lib/active_record/transactions.rb +360 -0
  133. data/lib/active_record/translation.rb +22 -0
  134. data/lib/active_record/validations.rb +83 -0
  135. data/lib/active_record/validations/associated.rb +43 -0
  136. data/lib/active_record/validations/uniqueness.rb +180 -0
  137. data/lib/active_record/version.rb +10 -0
  138. data/lib/rails/generators/active_record.rb +25 -0
  139. data/lib/rails/generators/active_record/migration.rb +15 -0
  140. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  141. data/lib/rails/generators/active_record/migration/templates/migration.rb +31 -0
  142. data/lib/rails/generators/active_record/model/model_generator.rb +43 -0
  143. data/lib/rails/generators/active_record/model/templates/migration.rb +15 -0
  144. data/lib/rails/generators/active_record/model/templates/model.rb +7 -0
  145. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  146. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  147. data/lib/rails/generators/active_record/observer/templates/observer.rb +4 -0
  148. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +25 -0
  149. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +12 -0
  150. metadata +242 -0
@@ -0,0 +1,65 @@
1
+ begin
2
+ require 'psych'
3
+ rescue LoadError
4
+ end
5
+
6
+ require 'erb'
7
+ require 'yaml'
8
+
9
+ module ActiveRecord
10
+ class Fixtures
11
+ class File
12
+ include Enumerable
13
+
14
+ ##
15
+ # Open a fixture file named +file+. When called with a block, the block
16
+ # is called with the filehandle and the filehandle is automatically closed
17
+ # when the block finishes.
18
+ def self.open(file)
19
+ x = new file
20
+ block_given? ? yield(x) : x
21
+ end
22
+
23
+ def initialize(file)
24
+ @file = file
25
+ @rows = nil
26
+ end
27
+
28
+ def each(&block)
29
+ rows.each(&block)
30
+ end
31
+
32
+ RESCUE_ERRORS = [ ArgumentError ] # :nodoc:
33
+
34
+ private
35
+ if defined?(Psych) && defined?(Psych::SyntaxError)
36
+ RESCUE_ERRORS << Psych::SyntaxError
37
+ end
38
+
39
+ def rows
40
+ return @rows if @rows
41
+
42
+ begin
43
+ data = YAML.load(render(IO.read(@file)))
44
+ rescue *RESCUE_ERRORS => error
45
+ raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
46
+ end
47
+ @rows = data ? validate(data).to_a : []
48
+ end
49
+
50
+ def render(content)
51
+ ERB.new(content).result
52
+ end
53
+
54
+ # Validate our unmarshalled data.
55
+ def validate(data)
56
+ unless Hash === data || YAML::Omap === data
57
+ raise Fixture::FormatError, 'fixture is not a hash'
58
+ end
59
+
60
+ raise Fixture::FormatError unless data.all? { |name, row| Hash === row }
61
+ data
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,156 @@
1
+ module ActiveRecord
2
+ # = Active Record Identity Map
3
+ #
4
+ # Ensures that each object gets loaded only once by keeping every loaded
5
+ # object in a map. Looks up objects using the map when referring to them.
6
+ #
7
+ # More information on Identity Map pattern:
8
+ # http://www.martinfowler.com/eaaCatalog/identityMap.html
9
+ #
10
+ # == Configuration
11
+ #
12
+ # In order to enable IdentityMap, set <tt>config.active_record.identity_map = true</tt>
13
+ # in your <tt>config/application.rb</tt> file.
14
+ #
15
+ # IdentityMap is disabled by default and still in development (i.e. use it with care).
16
+ #
17
+ # == Associations
18
+ #
19
+ # Active Record Identity Map does not track associations yet. For example:
20
+ #
21
+ # comment = @post.comments.first
22
+ # comment.post = nil
23
+ # @post.comments.include?(comment) #=> true
24
+ #
25
+ # Ideally, the example above would return false, removing the comment object from the
26
+ # post association when the association is nullified. This may cause side effects, as
27
+ # in the situation below, if Identity Map is enabled:
28
+ #
29
+ # Post.has_many :comments, :dependent => :destroy
30
+ #
31
+ # comment = @post.comments.first
32
+ # comment.post = nil
33
+ # comment.save
34
+ # Post.destroy(@post.id)
35
+ #
36
+ # Without using Identity Map, the code above will destroy the @post object leaving
37
+ # the comment object intact. However, once we enable Identity Map, the post loaded
38
+ # by Post.destroy is exactly the same object as the object @post. As the object @post
39
+ # still has the comment object in @post.comments, once Identity Map is enabled, the
40
+ # comment object will be accidently removed.
41
+ #
42
+ # This inconsistency is meant to be fixed in future Rails releases.
43
+ #
44
+ module IdentityMap
45
+
46
+ class << self
47
+ def enabled=(flag)
48
+ Thread.current[:identity_map_enabled] = flag
49
+ end
50
+
51
+ def enabled
52
+ Thread.current[:identity_map_enabled]
53
+ end
54
+ alias enabled? enabled
55
+
56
+ def repository
57
+ Thread.current[:identity_map] ||= Hash.new { |h,k| h[k] = {} }
58
+ end
59
+
60
+ def use
61
+ old, self.enabled = enabled, true
62
+
63
+ yield if block_given?
64
+ ensure
65
+ self.enabled = old
66
+ clear
67
+ end
68
+
69
+ def without
70
+ old, self.enabled = enabled, false
71
+
72
+ yield if block_given?
73
+ ensure
74
+ self.enabled = old
75
+ end
76
+
77
+ def get(klass, primary_key)
78
+ record = repository[klass.symbolized_sti_name][primary_key]
79
+
80
+ if record.is_a?(klass)
81
+ ActiveSupport::Notifications.instrument("identity.active_record",
82
+ :line => "From Identity Map (id: #{primary_key})",
83
+ :name => "#{klass} Loaded",
84
+ :connection_id => object_id)
85
+
86
+ record
87
+ else
88
+ nil
89
+ end
90
+ end
91
+
92
+ def add(record)
93
+ repository[record.class.symbolized_sti_name][record.id] = record
94
+ end
95
+
96
+ def remove(record)
97
+ repository[record.class.symbolized_sti_name].delete(record.id)
98
+ end
99
+
100
+ def remove_by_id(symbolized_sti_name, id)
101
+ repository[symbolized_sti_name].delete(id)
102
+ end
103
+
104
+ def clear
105
+ repository.clear
106
+ end
107
+ end
108
+
109
+ # Reinitialize an Identity Map model object from +coder+.
110
+ # +coder+ must contain the attributes necessary for initializing an empty
111
+ # model object.
112
+ def reinit_with(coder)
113
+ @attributes_cache = {}
114
+ dirty = @changed_attributes.keys
115
+ attributes = self.class.initialize_attributes(coder['attributes'].except(*dirty))
116
+ @attributes.update(attributes)
117
+ @changed_attributes.update(coder['attributes'].slice(*dirty))
118
+ @changed_attributes.delete_if{|k,v| v.eql? @attributes[k]}
119
+
120
+ run_callbacks :find
121
+
122
+ self
123
+ end
124
+
125
+ class Middleware
126
+ class Body #:nodoc:
127
+ def initialize(target, original)
128
+ @target = target
129
+ @original = original
130
+ end
131
+
132
+ def each(&block)
133
+ @target.each(&block)
134
+ end
135
+
136
+ def close
137
+ @target.close if @target.respond_to?(:close)
138
+ ensure
139
+ IdentityMap.enabled = @original
140
+ IdentityMap.clear
141
+ end
142
+ end
143
+
144
+ def initialize(app)
145
+ @app = app
146
+ end
147
+
148
+ def call(env)
149
+ enabled = IdentityMap.enabled
150
+ IdentityMap.enabled = true
151
+ status, headers, body = @app.call(env)
152
+ [status, headers, Body.new(body, enabled)]
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,167 @@
1
+ require 'active_support/concern'
2
+
3
+ module ActiveRecord
4
+ module Inheritance
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ # Determine whether to store the full constant name including namespace when using STI
9
+ class_attribute :store_full_sti_class
10
+ self.store_full_sti_class = true
11
+ end
12
+
13
+ module ClassMethods
14
+ # True if this isn't a concrete subclass needing a STI type condition.
15
+ def descends_from_active_record?
16
+ if superclass.abstract_class?
17
+ superclass.descends_from_active_record?
18
+ else
19
+ superclass == Base || !columns_hash.include?(inheritance_column)
20
+ end
21
+ end
22
+
23
+ def finder_needs_type_condition? #:nodoc:
24
+ # This is like this because benchmarking justifies the strange :false stuff
25
+ :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
26
+ end
27
+
28
+ def symbolized_base_class
29
+ @symbolized_base_class ||= base_class.to_s.to_sym
30
+ end
31
+
32
+ def symbolized_sti_name
33
+ @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
34
+ end
35
+
36
+ # Returns the base AR subclass that this class descends from. If A
37
+ # extends AR::Base, A.base_class will return A. If B descends from A
38
+ # through some arbitrarily deep hierarchy, B.base_class will return A.
39
+ #
40
+ # If B < A and C < B and if A is an abstract_class then both B.base_class
41
+ # and C.base_class would return B as the answer since A is an abstract_class.
42
+ def base_class
43
+ class_of_active_record_descendant(self)
44
+ end
45
+
46
+ # Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
47
+ attr_accessor :abstract_class
48
+
49
+ # Returns whether this class is an abstract class or not.
50
+ def abstract_class?
51
+ defined?(@abstract_class) && @abstract_class == true
52
+ end
53
+
54
+ def sti_name
55
+ store_full_sti_class ? name : name.demodulize
56
+ end
57
+
58
+ # Finder methods must instantiate through this method to work with the
59
+ # single-table inheritance model that makes it possible to create
60
+ # objects of different types from the same table.
61
+ def instantiate(record)
62
+ sti_class = find_sti_class(record[inheritance_column])
63
+ record_id = sti_class.primary_key && record[sti_class.primary_key]
64
+
65
+ if ActiveRecord::IdentityMap.enabled? && record_id
66
+ if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
67
+ record_id = record_id.to_i
68
+ end
69
+ if instance = IdentityMap.get(sti_class, record_id)
70
+ instance.reinit_with('attributes' => record)
71
+ else
72
+ instance = sti_class.allocate.init_with('attributes' => record)
73
+ IdentityMap.add(instance)
74
+ end
75
+ else
76
+ instance = sti_class.allocate.init_with('attributes' => record)
77
+ end
78
+
79
+ instance
80
+ end
81
+
82
+ protected
83
+
84
+ # Returns the class descending directly from ActiveRecord::Base or an
85
+ # abstract class, if any, in the inheritance hierarchy.
86
+ def class_of_active_record_descendant(klass)
87
+ if klass == Base || klass.superclass == Base || klass.superclass.abstract_class?
88
+ klass
89
+ elsif klass.superclass.nil?
90
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
91
+ else
92
+ class_of_active_record_descendant(klass.superclass)
93
+ end
94
+ end
95
+
96
+ # Returns the class type of the record using the current module as a prefix. So descendants of
97
+ # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
98
+ def compute_type(type_name)
99
+ if type_name.match(/^::/)
100
+ # If the type is prefixed with a scope operator then we assume that
101
+ # the type_name is an absolute reference.
102
+ ActiveSupport::Dependencies.constantize(type_name)
103
+ else
104
+ # Build a list of candidates to search for
105
+ candidates = []
106
+ name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
107
+ candidates << type_name
108
+
109
+ candidates.each do |candidate|
110
+ begin
111
+ constant = ActiveSupport::Dependencies.constantize(candidate)
112
+ return constant if candidate == constant.to_s
113
+ rescue NameError => e
114
+ # We don't want to swallow NoMethodError < NameError errors
115
+ raise e unless e.instance_of?(NameError)
116
+ end
117
+ end
118
+
119
+ raise NameError, "uninitialized constant #{candidates.first}"
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ def find_sti_class(type_name)
126
+ if type_name.blank? || !columns_hash.include?(inheritance_column)
127
+ self
128
+ else
129
+ begin
130
+ if store_full_sti_class
131
+ ActiveSupport::Dependencies.constantize(type_name)
132
+ else
133
+ compute_type(type_name)
134
+ end
135
+ rescue NameError
136
+ raise SubclassNotFound,
137
+ "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
138
+ "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
139
+ "Please rename this column if you didn't intend it to be used for storing the inheritance class " +
140
+ "or overwrite #{name}.inheritance_column to use another column for that information."
141
+ end
142
+ end
143
+ end
144
+
145
+ def type_condition(table = arel_table)
146
+ sti_column = table[inheritance_column.to_sym]
147
+ sti_names = ([self] + descendants).map { |model| model.sti_name }
148
+
149
+ sti_column.in(sti_names)
150
+ end
151
+ end
152
+
153
+ private
154
+
155
+ # Sets the attribute used for single table inheritance to this class name if this is not the
156
+ # ActiveRecord::Base descendant.
157
+ # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
158
+ # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
159
+ # No such attribute would be set for objects of the Message class in that example.
160
+ def ensure_proper_type
161
+ klass = self.class
162
+ if klass.finder_needs_type_condition?
163
+ write_attribute(klass.inheritance_column, klass.sti_name)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,49 @@
1
+ module ActiveRecord
2
+ module Integration
3
+ # Returns a String, which Action Pack uses for constructing an URL to this
4
+ # object. The default implementation returns this record's id as a String,
5
+ # or nil if this record's unsaved.
6
+ #
7
+ # For example, suppose that you have a User model, and that you have a
8
+ # <tt>resources :users</tt> route. Normally, +user_path+ will
9
+ # construct a path with the user object's 'id' in it:
10
+ #
11
+ # user = User.find_by_name('Phusion')
12
+ # user_path(user) # => "/users/1"
13
+ #
14
+ # You can override +to_param+ in your model to make +user_path+ construct
15
+ # a path using the user's name instead of the user's id:
16
+ #
17
+ # class User < ActiveRecord::Base
18
+ # def to_param # overridden
19
+ # name
20
+ # end
21
+ # end
22
+ #
23
+ # user = User.find_by_name('Phusion')
24
+ # user_path(user) # => "/users/Phusion"
25
+ def to_param
26
+ # We can't use alias_method here, because method 'id' optimizes itself on the fly.
27
+ id && id.to_s # Be sure to stringify the id for routes
28
+ end
29
+
30
+ # Returns a cache key that can be used to identify this record.
31
+ #
32
+ # ==== Examples
33
+ #
34
+ # Product.new.cache_key # => "products/new"
35
+ # Product.find(5).cache_key # => "products/5" (updated_at not available)
36
+ # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
37
+ def cache_key
38
+ case
39
+ when new_record?
40
+ "#{self.class.model_name.cache_key}/new"
41
+ when timestamp = self[:updated_at]
42
+ timestamp = timestamp.utc.to_s(:number)
43
+ "#{self.class.model_name.cache_key}/#{id}-#{timestamp}"
44
+ else
45
+ "#{self.class.model_name.cache_key}/#{id}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,40 @@
1
+ en:
2
+ # Attributes names common to most models
3
+ #attributes:
4
+ #created_at: "Created at"
5
+ #updated_at: "Updated at"
6
+
7
+ # Active Record models configuration
8
+ activerecord:
9
+ errors:
10
+ messages:
11
+ taken: "has already been taken"
12
+ record_invalid: "Validation failed: %{errors}"
13
+ # Append your own errors here or at the model/attributes scope.
14
+
15
+ # You can define own errors for models or model attributes.
16
+ # The values :model, :attribute and :value are always available for interpolation.
17
+ #
18
+ # For example,
19
+ # models:
20
+ # user:
21
+ # blank: "This is a custom blank message for %{model}: %{attribute}"
22
+ # attributes:
23
+ # login:
24
+ # blank: "This is a custom blank message for User login"
25
+ # Will define custom blank validation message for User model and
26
+ # custom blank validation message for login attribute of User model.
27
+ #models:
28
+
29
+ # Translate model names. Used in Model.human_name().
30
+ #models:
31
+ # For example,
32
+ # user: "Dude"
33
+ # will translate User model name to "Dude"
34
+
35
+ # Translate model attribute names. Used in Model.human_attribute_name(attribute).
36
+ #attributes:
37
+ # For example,
38
+ # user:
39
+ # login: "Handle"
40
+ # will translate User attribute "login" as "Handle"