Archive for the 'Uncategorized' Category
Handy ActiveRecord Migration Methods
We are undergoing a massive DB schema redesign. Much of the work is just tightening up the schema through optimizing indexes, setting default boolean and integer fields, and updating NULL allowed fields. Here is a little module I wrote to save massive amounts of code.
module MigrationHelper def index_exists?(table, lookup) lookup = Hash[:columns, Array(lookup)] unless lookup.is_a?(Hash) lookup.symbolize_keys! lookup.each{|key,value|lookup[key]=(value.is_a?(Array))?(value.collect{|v|v.to_s}):(value.to_s)} indexes(table).collect(&lookup.keys.first).include?(lookup.values.first) end def change_column_nulls(table_name, nullable, *column_names) column_names.each do |column_name| table_columns = columns(table_name) column_def = table_columns.select{|c|c.name == column_name.to_s} raise "Unknown column name #{column_name} for #{table_name}\nAvailable columns: #{table_columns.collect(&:name).to_sentence}" if column_def.empty? change_column table_name, column_name, column_def.first.type, :null => nullable end end def change_column_defaults(table_name, default, *column_names) column_names.each do |column_name| change_column_default table_name, column_name, default end end end
I fond it necessary to have the index_exists? method mainly for my development purposes. When I’m optimizing tables by doing complex indexes, I often do them right on the DB first before throwing them into a migration. By having this check I can easily skip over it if it already exists. It takes the same options as add_index. You can pass table and column names, or just table and index name. Here are some usage examples:
add_index :table, :column unless index_exists?(:table, :column) add_index :table, [:column1, :column2] unless index_exists?(:table, [:column1, :column2]) add_index :table, [:column1, :column2, :column3], :name => "some_index_name" unless index_exists?(:table, :name => "some_index_name")
The method change_column_nulls is used to mass change the NULL allowed columns for a given table. Really not much to it, but saves a lot of code over doing change_table or change_column. Here is the usage:
change_column_nulls :table, false, :column1, :column2
And lastly change_column_defaults is just a wrapper around change_column_default for mass assignment. Usage is the same as change_column_nulls passing the default values as the second argument. I thought about combining the two, but it didn’t offer very much savings.
These were tested using MySql 5. I’m not sure about the compatibility with other servers.
No commentsRJS redirect_to params contain &
I came across this today when I added a parameter to a RJS page.redirect_to call. It appears that prototype or rails is not properly handling the parameters when there are more than 2. I got around it by using a defined route in the routes.rb that looks like this:
map.route_name 'controller_name/action_name/:foo_id', :controller => 'controller_name', :action => 'action_name'
I had to change the redirect_to in my RJS file from this:
page.redirect_to page_recrawl_path(:foo_id => @foo_id, :bar_id => @bar_id, :bang => true)
To this:
page.redirect_to page_recrawl_path(@foo_id, {:bar_id => @bar_id, :bang => true})
Ruby on Rails background process: MySQL server has gone away
Using workling and starling to handle background tasks is very nice. Check out this link for info on setting it up. However, I encountered the error: “Mysql::Error: MySQL server has gone away” when accessing an external DB tables like users and roles. I found that someone recommended using verify_active_connections!, however the table the connection error occurred on was a HABTM table ‘user_roles’. I found that verify_active_connections will use the scope of the model/object you invoke it on. So the final solution was to do the following:
user.roles.verify_active_connections!
This will make sure users, user_roles, and roles all have valid connections. This error occurred using rails 2.0.1. It may be fixed in newer versions of ActiveRecord.
No commentsRuby sum array values for currency
I found this handy trick to take an array built from some hash values and spit out a currency. Here is what I used it for. Inside my model, I built some test items.
def self.test_items [{:price => "5.50", :weight => 10, :item_description => "Test item 1"}, {:price => "7.75", :weight => 15, :item_description => "Test item 2"}, {:price => "9.95", :weight => 20, :item_description => "Test item 3"}] end
I wanted to get a “Total Price” in the view, so I did the following. I created a method in my ApplicationHelper that looks like so
def total_for_cart(prices) number_to_currency(prices.inject(0){|sum, price| sum.to_f + price.to_f}) end
The above uses the Ruby inject method from the Enumerable class to simply add the float values. I’m also using the rails helper method number_to_currency for pretty formatting. Finally my view looks like this:
<p>Total: <%= total_for_cart(items.collect{|i| i[:price]}) %></p>
That simply collects the price from the items array and passes it to my helper method. Hope its helpful!
No commentsWelcome
Hello all,
I decided to move my old blog to a wordpress instance. Mephisto just wasn’t working out for me, regardless of my love for rails. Anyhow, I’ll slowly be moving stuff over from my old blog. Please stay tuned.
Thanks,
Shep
No comments