Wednesday, May 22, 2013

Profiling in Rails with Ruby's Profiler

This is a nifty trick:

rails c 2>&1 | tee profile.txt

Then:

require 'profile'
SomeClass.some_method
exit (or ctrl-d)

Then filter the output by your classname:

grep -E "SomeClass\#|cumulative   self|seconds    call" profile.txt
Which results in:

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  1.05     0.79      0.01        5     2.00     2.00  SomeClass#_validate_callbacks
  0.00     0.95      0.00       13     0.00     0.00  SomeClass#_create_callbacks
  0.00     0.95      0.00       13     0.00     0.00  SomeClass#_update_callbacks
  0.00     0.95      0.00       15     0.00     0.00  SomeClass#reflections
  0.00     0.95      0.00       12     0.00     0.00  SomeClass#_save_callbacks
  ...

Monday, March 25, 2013

RVM v1.x's .rvmrc set -e Workaround

So, I learned a fun fact about RVM v1.x today which is that if you put "set -e" in your .rvmrc, it will exit out of the terminal session when you try to backout of the directory via "cd ..". This will be fixed in RVM v2.

If what you are trying to do is stop executing the .rvmrc unless RVM switched the ruby and gemset correctly, you can just check it, e.g.:

rvm use ruby-1.9.3@awesome --create

# we'll make sure that it switched before installing things
if [ "$(~/.rvm/bin/rvm-prompt i v g)" == "ruby-1.9.3@awesome" ] ; then
    # other things here
fi

Note: I'd make "ruby-1.9.3@awesome" a variable, but IDea/Rubymine currently expects a certain format, so that wouldn't work.

Tuesday, March 19, 2013

restful_json: An Easy Way to Create Rails RESTful-ish JSON Services

restful_json reduces the amount of code that you need to write in your Rails controllers to implement declarative, featureful JSON service controllers for Javascript frameworks like AngularJS.

It should work with Rails 3.1+ and Rails 4. It uses Adam Hawkin's permitters, strong_parameters, and active_model_serializers, so it helps you act like you are using Rails 4.0, even if you're using Rails 3.1.

Check it out, it's finally in Rubygems. We've been using a slightly modded version in production for a while, and works great.

Common Ruby/Rails/Rack Vulnerability: params[:some_sym].to_sym

Symbols are great when they are well-defined, because you avoid String creation and don't tend to create as much GC churn. But, sometimes the tendency to use symbols for keys can be a bad thing.

Case in point is CVE-2013-1854, fixed in Rails 3.2.13, 3.1.12, and 2.3.18.

If you can't use one of those versions of Rails, at least use the workaround provided in that notice for ActiveRecord:

... change code that looks like this:

User.where(:name => params[:name])
to code like this:
User.where(:name => params[:name].to_s) 

But, it goes beyond that. This should serve as a warning to not ever convert significantly variable/unknown user-provided values to symbols, ever, if you want to avoid a similar vulnerability. When you create a symbol, it is going to stay around and not be garbage-collected, so allowing any thing the user wants to become a symbol is both a possible memory leak issue and a DoS vulnerability.

Change anything that would ever do the equivalent (directly or indirectly) of:

params[:some_sym].to_sym

to leave the value as a String:

params[:some_sym]

and do whatever else you need to do to ensure that user-defined values in part or whole don't become lots and lots of symbols.

Also, even though it may introduce a little extra churn, if for whatever reason you aren't sure that the value in params is a String, then use to_s, to_i, ... (any of the usual numeric conversions) on it, to attempt to enforce type.

Monday, February 11, 2013

Check StackOverflow Status

StackExchange was down briefly this morning of Feb 11, 2013. Status of StackExchange sites is available at: http://stackstatus.net/. Update: Of course, in the minute between me seeing they were down and posting this, now they are back up. :) They rock.


(images courtesy of stackoverflow.com)

Thursday, November 29, 2012

Working with Your Rails GitHub Fork

Note: Some of the commands listed here can really do some damage and screw you up, so be careful and learn what you are doing before blindly executing things.

Lets say you've read the great reference doc, Contributing to Ruby on Rails, and just forked Rails in Github, want to clone it locally, and want to keep it updated.

First clone it:

cd ~
mkdir github
cd github 
git clone git@github.com:my_user/rails.git
cd rails

Now you want to setup a remote to the original repo to fetch from later to update your copy:

git remote add rails git@github.com:rails/rails.git

Rails changes a lot. To update your version and apply any current changes on top of it, first you need to fetch and then rebase. Since we called the remote "rails" since that is the name of the user in Github. (If we had forked from https://github.com/twitter/bootstrap then we would have called it "twitter"):

git fetch rails

Check to see what branch you're on:

git branch

Let's assume you are on master, so:

git fetch rails
git rebase rails/master

Working directly with your master branch (not recommended)

The easiest thing to do is to work in your master. This is problematic, but it is what many might do at first, so let's see what that involves...

As you continue to work on it, if you want to get the latest and apply any changes you made atop it, you'd do that again.

So, again to check to see what branch you're on:

git branch

Then assuming you are in master:

git fetch rails
git rebase rails/master

That covers keeping everything up-to-date. So, let's assume you made some changes, added them, committed them, and pushed them (to your GitHub fork). Then you discussed it on the Rails core list/google group, did a pull request, and the core team decided not to take your contribution. You don't want to get rid of the commit, because then people wouldn't be able to see your commit in Github when looking back at the denied pull request, just in case they want to use some of your code themselves. But you need to get master looking like the original master Rails.

First find the long hash key of the last commit before your changes were applied. Please be sure to fetch and rebase first so we have the best chance to be fully up-to-date. To find the commit hash of the last guy outside of you (and your team if more than one worked on your rejected commit(s)) that made the last commit to remote Rails master:

git log

Then reset your head to that commit, which will abandon that/those commit(s) you made locally:

git reset --hard (put hash of most recent commit that wasn't yours here)

Then push this back to your fork, abandoning that/those commit(s) you made. This assumes that Github is origin (you can look at .git/config if you want to check) and that you are pushing to the master branch in your rails fork:

git push -f origin master
Painful, huh? Well, not too bad, but if you need to work on two different Rails patches at once, that won't work. So let's talk about the other way...

Working in feature branches in your fork and then doing pull requests from it to Rails master (recommended)

First create a remote feature branch. I like the gbranch command from my git-scripts project, so I'll show what it looks like if using it:

gbranch add_something_incredible_to_rails
If you are working in your branch and want to keep it up-to-date with remote rails master and apply your fork's feature branch changes on top, do:

git fetch rails
git rebase rails/master

So, let's assume you made some changes, added them, committed them, and pushed them (to your GitHub fork). Then you discussed it on the Rails core list/google group, did a pull request, and the core team decided not to take your contribution. Don't delete that branch because it will be referenced from the pull request in GitHub and people might want to take a look.

When you want to do another new feature, just gbranch again, and at anytime use gbranch to switch between features.

Thanks to:

Wednesday, November 21, 2012

Ruby/Rails Tips

A few Ruby/Rails tips:

  • Avoid references to other Rails classes outside of methods if the class is autoloaded by Rails if that might cause all of the web of classes to be loaded at once. Instead refer to those classes with strings, symbols, etc. E.g. though you can use class_name: SomeModel in a Rails association, use class_name: "SomeModel".
  • Within methods, use symbols or classes/constants rather than strings if possible, unless it is something dynamic, since defining a string will usually create a new instance of it whereas symbols and constants stay forever (well... kind of). Also, constants and symbols also compare really nicely. Note that you may have problems sorting on constants/classes, so it is better to use symbols or strings if need to sort.
  • For incoming user-defined data, don't convert the strings into symbols (e.g. don't convert the value of a request param to a symbol). Symbols stay for the life of the application, so that can allow people to make your application run out of memory by sending in a lot of requests with varying large request param values.
  • Be careful when using param values in ActiveRecord queries. See CVE-2013-1854 which affects Rails 3.2.x, 3.1.x, 2.3.x prior to 3.2.13, 3.1.12, 2.3.18.
  • If you have a string that shouldn't be changed, you probably want to freeze it. Note that Ruby will freeze certain things automatically like hash keys. Strings stored in constants may be a good thing to freeze, e.g. SOME_CONSTANT='something'.freeze. Some other tips here: http://engineering.twitter.com/2011/05/faster-ruby-kiji-update.html
  • You must use double quotes around string definitions that have #{…} in them. Otherwise, I tend to use single quotes because it looks cleaner, but there is no performance difference, in Ruby 1.8.7 and 1.9.3 at least: http://stackoverflow.com/a/1842829/178651
  • When in Rails, put modules and classes in a directory path that corresponds to the fully-qualified path under the autoloaded directory (app/models, app/controllers, etc.), because when Rails autoloads and reloads, that is where it is looking for it.
  • Often class variables (@@) being altered by instance methods are a bad thing, just like static variables in object instance methods in Java.
  • Global variables ($) are usually not a good idea. E.g, you cannot easily differentiate between a global boolean variable that is false and one that hasn't been set.
  • In Rails, you can use class_attribute instead of class variables to put attributes on a class. Rails convention is to use an underscore in front for internal variables not meant to be set outside of that gem, framework, etc. but you still must try to avoid conflicts. Be aware that Rails class_attribute values belong to the class or module, so if you put a class_attribute on a module and include that modules in other classes, they may be sharing a hash/array stored in a class_attribute of the module. This can be a problem, obviously.
  • Often uppercase-and-underscored constants in Ruby don't provide the value that they would in language that do compile-time checking like Java. Consider using symbols in Ruby instead, which are lighter weight, unless you need to store a value.
  • Unless you want loading/autoloading to fail when trying to load a class or module if the parent module was not defined, don't define modules or classes like: module Parent::Child or class Parent::Child. Instead use: module Parent; module Child or module Parent; class Child.