Method_missing in a AR child only catching 1 of several call

Hello -

Why does a view including the following fragment:

 <% for column in User.content_columns %>
   <td><%=h user.send(column.name) %></td>
 <% end %>

and the User model having the following defined:

 def method_missing(meth_id, *args, &blk)
   meth_name=meth_id.id2name
   puts("Calling: #{meth_name}")
   super
 end

only result in the following output of one method call when there are
several columns/attributes in the users table:

 Calling: name

On 2/11/07, Aakash C. [email protected] wrote:

 def method_missing(meth_id, *args, &blk)
   meth_name=meth_id.id2name
   puts("Calling: #{meth_name}")
   super
 end

only result in the following output of one method call when there are
several columns/attributes in the users table:

 Calling: name

Hi Aakash,

ActiveRecord::Base defines read methods lazily. That is, until you
call a method to read an attribute, the method won’t exist. Call a
method to read an attribute, and it’ll hit AR::B’s method_missing
hook, which defines all the read methods, and hence, subsequent calls
to read methods won’t trigger method_missing. You can witness the
effect in script/console:

Thing.instance_methods(false)
=> []
Thing.new.name
=> nil
Thing.instance_methods(false)
=> [“id?”, “name?”, “name”, “value”, “value?”]

I’m not sure what you’re trying to do, but if you explain it, someone
might be able to find something that works. :slight_smile: (Assuming this is a
problem for you.)

Regards,
George.

George O. wrote:
.
.

I’m not sure what you’re trying to do, but if you explain it, someone
might be able to find something that works. :slight_smile: (Assuming this is a
problem for you.)

Regards,
George.

Hey George - Thanks for the quick response.

I’d like intercept all method calls to my models accessing an attribute
in order to implement an attribute level authorization scheme - similar
to the J2EE analog which is a pain but works (specified in ejb-jar.xml).

I think I found a way to configure rails to not generate the ENTIRE
method list lazily - but the implication is that I’ll loose on
performance:

config.active_record.generate_read_methods = false (instead of the
default value of true)

Anyone got any Ideas?

Regards,
Aakash

On 2/11/07, AC CE [email protected] wrote:

config.active_record.generate_read_methods = false (instead of the
default value of true)

Anyone got any Ideas?

Have you looked around at the existing model-level authentication
plugins? I think some do attribute-level authorization. e.g., [1].

If that doesn’t fly for you, I’m not sure what the best way to do this
is. Once you’ve generated the read methods, they’re available via
ModelName.read_methods. Perhaps you can override these. I don’t
think that’s particularly watertight, though. #read_attribute, for
example seems to pull things directly out of the @attributes hash
inside the active record instances directly rather than going through
the read methods. Perhaps you could hook into the #[] method on this
hash, but that’s getting pretty nasty!

class ActiveRecord::Base
def initialize_with_authorization_check(*args)
initialize_without_authorization_check(*args) do |*args|
class << @attributes
def
# … authorization check …
super
end
def []=(name, value)
# … authorization check …
super
end
end
yield(*args) if block_given?
end
end
alias initialize_without_authorization_check initialize
alias initialize initialize_with_authorization_check
end

(Totally untested.)

[1] http://perens.com/FreeSoftware/ModelSecurity/

George.