Ruby on rails development tips
Rails is great for getting ideas prototyped super fast. These tips will slow down development and make apps less portable, but definatly improve speed your system
Ruby on rails coding style:
- Try to avoid the excess use of helpers since it adds overhead.
- You may consider to use memcached to cache your model and library computation results.
- Use a custom configuration file for passwords and API keys instead of storing them in your Subversion repository. Use YAML and mirror the style of database.yml.
- Use constants where needed. Instead of repeating strings like the address of your customer service reply email, set it once in a constant (in environment.rb or the appropriate environment file) and use that throughout your application.
- Keep time in UTC. A no brainer, and easy to do.
- Don’t loop through ActiveRecord models inside other models. Use eager loading if you need to work with multiple associated models. Better yet, write a custom SQL query and let the database do the work for you.
- Beware of binary fields. By default, all fields are returned with queries, including the full contents of any binary fields. Use :select to pull out only the fields you need.
- Write tables to cache data for reports that span months and years. It’s much faster than re-generating a year’s worth of reports every time a page is loaded.
- Create a table with a list of country names. By default, Rails uses strings for selects and lists of countries, which doesn’t work well for reporting or database consistency between models.
- Avoid bloated controllers. Instead of piling actions into a controller, limit yourself to 10 actions per controller, then rethink your design.
- Keep your controllers and views skinny. In general, most of your code should be in your models, not your controllers or views.
- Don’t store objects in the session. Use integers or short strings if necessary, then pull the appropriate object out of the database for the duration of a single request.
- Use ar_mailer to queue bulk emails instead of sending them during the Rails response cycle.
- Monitor your servers with the exception_notification plugin, munin, monit, or other tools.
- Test-drive your development.
- Profile your code. The ruby-prof gem and plugin helped me make an application three times faster with only minimal changes to the code.
- Minimize graphic-related dependencies. If your application only needs to make a few thumbnails, don’t waste memory by importing large graphics libraries. Look at mini-magick or image_science for lightweight thumbnailing.
- Avoid excessive repeated rendering of small partials.
- Use CSS instead of inline tags to apply selective styling.
- Use attr_protected :fieldname in models to keep database fields from being manipulated from forms (or from any calls to Model.update_attributes(params[:model])).
- Use Ruby classes and inheritance to refactor repeated controller code.
- Use unobtrusive Javascripting techniques to separate behavior from markup.
- Package self-sufficient classes and modules as plugins or RubyGems.
- Cache frequently accessed data and rendered content where possible.
- Write custom Test::Unit assertions or rSpec matchers to help with debugging test suite errors.
- Rotate the Rails and Mongrel logfiles using the logrotate daemon on Linux.
- Automate deployment and maintenance with Capistrano or Vlad.
- Keep method bodies short. If a method is more than 10 lines long, it’s time to break it down and refactor.
- Run flog to determine overly complex methods and clases.
- Don’t use too many conditionals. Take advantage of case statements and Ruby objects to filter instead of multiply-nested if statements.
- Become familiar with the most popular plugins. Instead of re-implementing the wheel, save yourself some time by using well tested, popular plugins.
Some tips for Mysql Database
- First, a rule of thumb: Development boxes are faster than production boxes. If it’s acceptably fast locally, then it’ll probably be a turtle in production.
- Use Model.find_by_sql or Model.count_by_sql whenever possible.
Slow: Person.find_by_name(’JoeyJoeJoe’)
Fast: Person.find_by_sql(”SELECT person.* WHERE person.name = ‘JoeyJoeJoe’”) - Don’t put keys, IDs, or other numbers within quotes in your Finds
Slow: WHERE id = “1234″
Fast: WHERE id = 1234 - Only request the specific database column/model attribute you want
Slow: Person.find_by_name(’JoeyJoeJoe’).height
Fast: Person.find_by_sql(”SELECT person.height WHERE person.name = ‘JoeyJoeJoe’”). Put indexes on all these columns/attributes. - Use connection.insert, connection.update, connection.delete for database transactions performed on an array of models or transactions that don’t need the overhead of a model.
- Slow: …WHERE table_1.id = table_2.table1_id…
Fast: …table_1 JOIN table_2 ON table1.id = table_2.table1_id…. - Many tiny database transactions are faster than 1 big one
Slow: stuff = Stuff.find_by_sql(”SELECT everything.* FROM everything JOIN (box_1, box_2) ON (everything.id = box_1.everything_id box_2.box1_id = box_1.id”)
Fast: boxes = Boxes.find_by_sql(”SELECT box_1.everything_id FROM box_1 JOIN box_2 ON box_2.box1_id = box_1.id”)
followed by
boxes.each do |box_1|
stuff = Stuff.find_by_sql(”SELECT everything.* FROM everything WHERE id = #{box_1.everything_id}
end - If you’re running the InnoDB datastore (vs MyISAM) try cranking up your innodb_buffer_pool_size. I say start by doubling it. Seriously.
- Again, if you’re running InnoDB and doing a anything more involved than the simplest ORDER BY, try cranking up your sort_buffer_size and read_rnd_buffer_size to something in the double-digit M range.
- Also, if you’re comparing datastore engines, MyISAM has full text search, InnoDB doesn’t. So you’ll need a clever work around. There are a number of them.
- Store sessions in the database (or at least not on disk, which is the default).
- Use database indexes to speed up queries. Rails only indexes primary keys, so you’ll have to find the spots that need more attention.
- Avoid dynamic finders like MyModel.find_by_*. While using something like User.find_by_username is very readable and easy, it also can cost you a lot. In fact, ActiveRecord dynamically generates these methods within method_missing and this can be quite slow.
- Don’t use ActiveRecord’s serialize option to store large objects in database fields.
Ruby’s Garbage Collection
is strongly advised and will improve the speed of your Ruby and Rails applications significantly.
Related Posts
Tags: Development, optimization, ror tips, ruby on rails, tips
Viewed: 1,911 views

September 14th, 2008 at 9:12 am
Have you done benchmarks to prove that dynamic finders (like find_by_*) are really that much slower? ActiveRecord generates the method in method_missing once, and then after that it’s like calling a regular method.
But I suppose if that kind of speed is really necessary for you, you could change this:
Person.find_by_sql(”SELECT person.height WHERE person.name = ‘JoeyJoeJoe’”)
to:
connection.select_value “SELECT person.height WHERE person.name = ‘JoeyJoeJoe’”
AR::Base.find_by_sql will instantiate a model, even for your single field.
I’m a little curious about your comment on dev boxes being faster than production boxes. In my experience (with engine yard at least), it’s the complete opposite. However, queries with hundreds of thousands of rows are definitely much slower than my local tables with just 5. But I’ve found that apps with indexed tables, as you suggest, spend more time rendering the view than fetching from the database.
September 15th, 2008 at 1:47 pm
[...] An interesting list of Rails tips to wander through. [...]