public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Changed ActiveRecord attributes to respect access control.

Signed-off-by: Michael Koziarski <michael@koziarski.com>
[#1084 state:committed]
Adam Milligan (author)
Sun Sep 21 01:03:09 -0700 2008
NZKoz (committer)
Wed Sep 24 10:40:07 -0700 2008
commit  4d9a7ab5f5c28820e0b076f9ca44bdd20e19e6ea
tree    2fbd6389b39e962d3233df236eb5f6344264454b
parent  a78ec93036644c41f936128a2b6d52f3136ad64c
...
232
233
234
 
 
 
 
235
236
237
...
334
335
336
337
 
338
339
340
 
 
341
342
343
...
232
233
234
235
236
237
238
239
240
241
...
338
339
340
 
341
342
343
344
345
346
347
348
349
0
@@ -232,6 +232,10 @@ module ActiveRecord
0
     def method_missing(method_id, *args, &block)
0
       method_name = method_id.to_s
0
 
0
+      if self.class.private_method_defined?(method_name)
0
+        raise NoMethodError("Attempt to call private method", method_name, args)
0
+      end
0
+
0
       # If we haven't generated any methods yet, generate them, then
0
       # see if we've created the method we're looking for.
0
       if !self.class.generated_methods?
0
@@ -334,10 +338,12 @@ module ActiveRecord
0
     # <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
0
     # which will all return +true+.
0
     alias :respond_to_without_attributes? :respond_to?
0
-    def respond_to?(method, include_priv = false)
0
+    def respond_to?(method, include_private_methods = false)
0
       method_name = method.to_s
0
       if super
0
         return true
0
+      elsif self.private_methods.include?(method_name) && !include_private_methods
0
+        return false
0
       elsif !self.class.generated_methods?
0
         self.class.define_attribute_methods
0
         if self.class.generated_methods.include?(method_name)
...
58
59
60
61
 
62
63
64
65
66
 
67
68
69
70
71
72
73
 
74
75
76
...
80
81
82
83
 
84
85
86
...
228
229
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
232
233
...
244
245
246
 
 
 
 
 
 
 
 
 
247
...
58
59
60
 
61
62
63
64
65
 
66
67
68
69
70
71
72
 
73
74
75
76
...
80
81
82
 
83
84
85
86
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
...
278
279
280
281
282
283
284
285
286
287
288
289
290
0
@@ -58,19 +58,19 @@ class AttributeMethodsTest < ActiveRecord::TestCase
0
 
0
   def test_kernel_methods_not_implemented_in_activerecord
0
     %w(test name display y).each do |method|
0
-      assert_equal false, ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
0
+      assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
0
     end
0
   end
0
 
0
   def test_primary_key_implemented
0
-    assert_equal true, Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
0
+    assert Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
0
   end
0
 
0
   def test_defined_kernel_methods_implemented_in_model
0
     %w(test name display y).each do |method|
0
       klass = Class.new ActiveRecord::Base
0
       klass.class_eval "def #{method}() 'defined #{method}' end"
0
-      assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
0
+      assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
0
     end
0
   end
0
 
0
@@ -80,7 +80,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
0
       abstract.class_eval "def #{method}() 'defined #{method}' end"
0
       abstract.abstract_class = true
0
       klass = Class.new abstract
0
-      assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
0
+      assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
0
     end
0
   end
0
 
0
@@ -228,6 +228,40 @@ class AttributeMethodsTest < ActiveRecord::TestCase
0
     assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes 
0
   end
0
 
0
+  def test_read_attributes_respect_access_control
0
+    privatize("title")
0
+
1
+    topic = @target.new(:title => "The pros and cons of programming naked.")
0
+    assert !topic.respond_to?(:title)
0
+    assert_raise(NoMethodError) { topic.title }
0
+    topic.send(:title)
0
+  end
0
+
0
+  def test_write_attributes_respect_access_control
0
+    privatize("title=(value)")
0
+
0
+    topic = @target.new
0
+    assert !topic.respond_to?(:title=)
0
+    assert_raise(NoMethodError) { topic.title = "Pants"}
0
+    topic.send(:title=, "Very large pants")
0
+  end
0
+
0
+  def test_question_attributes_respect_access_control
0
+    privatize("title?")
0
+
0
+    topic = @target.new(:title => "Isaac Newton's pants")
0
+    assert !topic.respond_to?(:title?)
0
+    assert_raise(NoMethodError) { topic.title? }
0
+    assert topic.send(:title?)
0
+  end
0
+
0
+  def test_bulk_update_respects_access_control
0
+    privatize("title=(value)")
0
+
0
+    assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
0
+    assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
0
+  end
0
+
0
   private
0
   def time_related_columns_on_topic
0
     Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
0
@@ -244,4 +278,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
0
     Time.zone = old_zone
0
     ActiveRecord::Base.time_zone_aware_attributes = old_tz
0
   end
0
+
0
+  def privatize(method_signature)
0
+    @target.class_eval <<-private_method
0
+      private
0
+      def #{method_signature}
0
+        "I'm private"
0
+      end
0
+    private_method
0
+  end
0
 end

Comments

Oh, there are cons?

NZKoz Thu Sep 25 00:18:29 -0700 2008

Indeed, it’s frowned upon at community code drives or in the enterprise.

Programming naked isn’t enterprise ready

supaspoida Thu Sep 25 00:29:36 -0700 2008

Cons: moment of panic as you rush to get clothed when the doorbell rings.

nbibler Thu Sep 25 06:52:08 -0700 2008

Cons: the look you receive from your wife when she returns home from work at the end of the day, and there you are.

smartocci Thu Sep 25 07:37:51 -0700 2008

Cons: forgetting that your skype was set to video chat….

nickh Thu Sep 25 11:07:40 -0700 2008

Cons: pair programming and standup meetings

rotor Thu Sep 25 11:12:24 -0700 2008

Cons: a vinyl chair

amyhoy Thu Sep 25 11:14:07 -0700 2008

cons: crack-sweat + chair.

I win.

(Being non-enterprise-ready is a pro, in my book.)

masterkain Thu Sep 25 11:15:57 -0700 2008

Cons: having adeona running, your macbook gets stolen and police look at photos taken to identify the thief.

ggoodale Thu Sep 25 11:25:27 -0700 2008

Cons: Near nuclear temperatures emanating from the bottom of your MacBook Pro when Time Machine kicks in.

mtodd Thu Sep 25 11:40:41 -0700 2008

Pros: air flow!

Someone had to.

randito Thu Sep 25 15:13:17 -0700 2008

Pros: My plugin hit your mencache. Cons: It was a miss.

raggi Thu Sep 25 15:18:17 -0700 2008

Cons:

def test_something send :something end

describe ‘something’ do before do @obj.module_eval { public :something } end it ‘is a pain in the ass to test’ { true.should.eql(true) } it …. end

;-P

augustl Fri Sep 26 01:43:35 -0700 2008

Pros: Makes tabbing to porn sites when tests are running a lot more convenient

henrik Fri Sep 26 03:09:48 -0700 2008

leethal: Those are supposed to be swords: http://xkcd.com/303/

lenary Thu Oct 09 14:27:19 -0700 2008

Cons: pubes in your keyboard! Pros: Easier to have sex during tests!