2
Oct

How to kill cache buster (those random numbers after assets)

2nd October 2008 | added by: b.kosmowski

Recently together with TGN we wrote few lines that finally allow proper opeartion of browser cache :)

Here it is (we’ve actually placed in one of initializers)…


module ActionView
module Helpers
module AssetTagHelper
def rewrite_asset_path_with_cache_buster(source)
if RAILS_ENV == "production" || RAILS_ENV == "development_cache"
return source
else
rewrite_asset_path_without_cache_buster(source)
end
end
alias_method_chain :rewrite_asset_path, :cache_buster
end
end
end
26
Sep

Caching methods with ActiveSupport::Memoizable

26th September 2008 | added by: Tomasz Bąk

Recently Marek posted on caching methods in rails models. Guess what, there is a build in tool in rails that does just that, and is called ActiveSupport::Memoizable. You can read more about it here.

Here are some quick examples how to use it:


# somewhere inside the class
extend ActiveSupport::Memoizable
def zipcode_and_name
"#{zipcode} #{name}"
end
memoize :zipcode_and_name

def some_method(*args)
# some calculations
end
memoize :some_method
26
Sep

How to validate bank account number

26th September 2008 | added by: b.kosmowski

…at least for polish accounts ;) It is just a matter of country code.

Just use this small extension, and you’ll have new validator, validates_as_account_number, available :)


module ActiveRecord
module Validations
module ClassMethods

def validates_as_account_number(*attr_names)
configuration = { :message => "is not valid account number" }
configuration.update(attr_names.extract_options!)
validates_each(attr_names, configuration) do |record, attr_name, value|
record.errors.add(attr_name, configuration[:message]) unless check_account_number_correctness(value)
end
end

protected

def check_account_number_correctness(account_number="")
account_number = account_number.to_s.gsub(" ","")
return false unless account_number.match(/^\d{26}$/)
#TODO Make it configurable? (country code)
account_number += "2521" + account_number.first(2)
account_number = account_number[2..account_number.length].to_i
return ((account_number % 97) == 1)
end

end
end
end
23
Sep

How to write a custom callback

23rd September 2008 | added by: b.kosmowski

Based on sample from http://snippets.dzone.com/posts/show/5226

Sometimes we would wish for some custom callbacks to keep things tidy in models or just for making integration of plugins much easier. As there is almost a complete set of callbacks that are triggered before save, I’ve concentrated on callbacks that would happen after save, and will be triggered on basis of what has been changed in record, or what is the status of this record.

In the case presented we will trigger after_completed callback, when record’s name field is set to “hehe” after save.


module ActiveRecord
#Make some meaningfull name for module you will include, to make things tidy
module PaymentProcessorCallbacks

def self.included(base)
base.class_eval do
#Define alias method chain which will seamlesly override :create_or_update method (or other methods if you wish)
alias_method_chain :create_or_update, :payment_processor_callbacks

#Merge your new callback (after_completed in this case) to callback chain
def self.after_completed(*callbacks, &block)
callbacks << block if block_given? #add the block to the array of callback functions if a block was passed
write_inheritable_array(:after_completed,callbacks)
end

define_callbacks :after_completed
end
end

#the instance method, although not recomended is avaliable for overriding
#also if you wanted to have a callback that always did something say add the users's id to the object
#you could always code that in here and remove the class above
def after_completed() end

def create_or_update_with_payment_processor_callbacks
#store result of generic method to return it l8r
result = create_or_update_without_payment_processor_callbacks
#execute your callback, based on some condition. Remember, that in self you have your saved object.
if self.name == "hehe"
callback(:after_completed)
end
#return the result from generic create_or_update method
return result
end

end

#Include your module into base_class which will trigger self.inlcuded(base) method, therefore "registering" your new callback
class Base
include PaymentProcessorCallbacks
end

end
19
Sep

Caching model methods in Rails

19th September 2008 | added by: Marek Kowalcze

Just to remember how easly You can cache particular method in your model.

We have some nasty method, which generates many queries to DB :) in Category model:


def popular_subcategories_db
self.leaves.map{|l| [l.sales_profiles.size, l.name]}.sort.reverse[0..2].map{|subc| "#{subc[1]}"}.join(' — ')
end

so we make a getter for it:


def popular_subcategories
Rails.cache.fetch("popular_subcategories_db_#{self.id}") { popular_subcategories_db }
end

Now, in log after first reqest we can see:


Cache miss: popular_subcategories_db_4 ({})
[4;35;1mCategory Load (0.000000)[0m   [0mSELECT * FROM "categories" WHERE (1 = 1 AND (lft BETWEEN 345 AND 354) AND lft + 1 = rgt) ORDER BY lft[0m
[4;36;1mSQL (0.000000)[0m   [0;1mSELECT count(*) AS count_all FROM "sales_profiles" WHERE ((sales_profiles.category_id = 208)) [0m
[4;35;1mSQL (0.000000)[0m   [0mSELECT count(*) AS count_all FROM "sales_profiles" WHERE ((sales_profiles.category_id = 228)) [0m
Cache write (will save 0.03100): popular_subcategories_db_4

after another one, we get only:


Cache hit: popular_subcategories_db_4 ({})

Nice!

taken from http://railscasts.com/episodes/115

EDIT: I found that when You cache ActiveRecord models, retrieved with complicated queries with joins, some of their association methods are missing after read from cache. !

Client Guide (pdf)