I’ve been working on an admin panel for a certain Rails app. One of the most common tasks to writing an admin panel is to generate a table where each column is a different attribute for your model. This is easy to do, but very tedious.
To simplify the task, I looked at metaprogramming. Metaprogramming with Ruby/Rails is very slick. I could generate a table for an arbitrary ActiveRecord starting with this code:
After a few basic iterations, I found that dynamically calling methods is 1) not reliable and 2) inhibits customization. So I found middle ground.
I wrote a basic Sinatra app that generates ERB templates given an ActiveRecord model. So far it will generate a table and a form for any model.
The app makes as little assumptions as possible, it simply takes care of the more tedious aspects of writing an admin panel.
Comments 5
Have you heard about Lipsiadmin? See http://github.com/Lipsiasoft/lipsiadmin
Posted 03 May 2010 at 5:57 am ¶Cool! i like the idea of using sinatra and rails together.
Posted 03 May 2010 at 6:20 am ¶Lipsiadmin looks very slick. I don’t want to knock any of the other solutions, they just weren’t right for what I wanted to accomplish.
Posted 03 May 2010 at 4:48 pm ¶Hi Alan,
which problems did you encounter with dynamically calling methods? This should work without any problems and I’m using it very, very often.
By the way, instead of find(:all, …)[0] you could do find(:first, …) or just first(…). For usage with dynamic data, you should write your conditions like the following because ActiveRecord will then protect you of SQL injections.
user = User.first(:conditions => ["users.name = ?", 'Alan'])
Using send(method_name) instead of method(method_name).call is faster because Ruby doesn’t have to create a method object for each call.
User.attribute_names.each {|attribute| user.send(attribute)}
Instead of @klass = eval(name) you may want to use @klass = name.constantize (which needs active support which you have anyway because of active record)
Your decamelize method would be shorter as by doing @name.to_s.tableize
Still, a good starting point and helpful/motivating to see others having similar problems and solutions.
Posted 05 May 2010 at 1:32 pm ¶Benjamin
Thanks for the tips, Benjamin!
Posted 05 May 2010 at 4:08 pm ¶My problems with dynamic method calling are summarized here: http://stackoverflow.com/questions/2687244/ruby-dynamically-calling-available-methods-raising-undefined-method-metaprogram
In a nutshell, methods like #created_at were raising no_method_errors even though they clearly are attributes.
The Inflector methods from ActiveSupport definitely do make life easier, it just never occurred to me that they were made available via ActiveRecord. Or can I simply throw in a require ‘activesupport’?
Regarding #send vs #method (#call), I’m glad I now know which one is faster, but considering that these tables get generated once, it shouldn’t be a significant performance hit.
I really appreciate the feedback though.
Post a Comment