Advanced acts_as_list scope with multiple columns
March 23, 2008
I just ran across a problem that I'm sure very few other people will encounter, but if I can help just one googler....
Scenario
You are using acts_as_list, and you want to scope your list by more than one column and one of the columns is a reserved word. You went to the rails documentation page for acts_as_list
class Element < ActiveRecord::Base
belongs_to :page
acts_as_list :scope => 'page_id = #{page_id} and `group` = \'#{group}\' '
end
Whoa - that's some ugly code. Let's see what's happening:
- The string you pass in to :scope is used to dynamically create a method called "scope_condition" with the contents of the string
- The :scope has to be in single quotes so that the contents of the #{} blocks don't get evaluated
- The word "group" has to be in special quotes, otherwise it will throw a MYSQL error
There are a number of problems with the code above - namely:
- The combination of single, double and angled quotes makes it very difficult to read
- The angled-quotes will not work for every database adapter
- The string contains #{} blocks, but they are not evaluated - instead they are evaluated later
The fix
Making the code database-independent is easy. Rails provides a method on every connection called "quote_column_name" which adds the correct quotes for whichever database adapter you are using. The connection object is a part of every Active Record instance, so the following line does the trick:
class Element < ActiveRecord::Base
belongs_to :page
acts_as_list :scope => 'page_id = #{page_id} AND #{connection.quote_column_name("group")} = \'#{group}\' '
end
Making the code easier to read is almost as simple - just define your own "scope_condition" method. The final code will look like this:
class Element < ActiveRecord::Base
belongs_to :page
acts_as_list
# scope_condition for acts_as_list
def scope_condition
"page_id = #{page_id} AND #{connection.quote_column_name("group")} = #{quote_value(group)}"
end
end
Now we're talkin'. The scope_condition is now database-independent, the quotes make sense and programs like TextMate will highlight the syntax appropriately.
References
- http://zigotos.ca/2007/10/25/multiple-scopes-values-for-acts_as_list/
- http://api.rubyonrails.org/classes/ActiveRecord/Acts/List/ClassMethods.html