Posted by Randy
on June 04, 2009
I had a need to find items that were similar to an item. I looked at acts_as_recommendable, and while this was very nice plugin, it was too slow when working with large data sets. I also decided that the results I needed didn’t need to be scientifically accurate, just a rough match. So I created this plugin to allow for a very elementary way to find items that are similar to the object you are working with. This works best when used with a has_many :through relationship.
Basically all it is doing is looking for other objects of the same class, that have some related value.
Git it here: http://github.com/freezzo/acts_as_similar/tree/master
Example 1
=========
Look for similar playlists, using the videos as what defines similarity.
This will look for all playlists that have a similar video as the playlist you are looking against.
class Playlist
has_many :playlists_videos
has_many :videos, :through => :playlists_videos
acts_as_similar :videos
end
Example 2
=========
Look for similar playlists, using the title of the playlist as the similarity item.
This will look for all playlists that have a similar title as the playlist you are looking against.
class Playlist
has_many :playlists_videos
has_many :videos, :through => :playlists_videos
acts_as_similar :field => :title
end
Example 3
=========
Look for similar playlists, using the video_id of the playlists_videos as the similarity item.
This will look for all playlists that have a similar video_id as the playlist you are looking against.
class Playlist
has_many :playlists_videos
has_many :videos, :through => :playlists_videos
acts_as_similar :playlists_videos, :field => :video_id
end
Execute
=========
@playlist = Playlist.first
@playlist.similar
Note: This is a work in progress.
Posted by Randy
on May 20, 2009
So I have been using a nice plug-in that will allow me to using :select when using :include, and not have it pull the entire data set. You can add the plug-in to your app like this:
script/plugin install git://github.com/blythedunham/eload-select.git
Here are some ways to use the plug-in:
Employee.find :all,
:select => 'addresses.city, address.state, employees.*',
:include => :address
Employee.find :first,
:select => 'now() as current_time, addresses.city, DATE(addresses.created_at) as addresses.created_at, employee.*',
:include => :address
Employee.find :all,
:select => 'addresses.city, employees.name, employees.start_date',
:include => :address
Examples taken from:
http://www.snowgiraffe.com/tech/329/eager-loading-select-plugin-when-select-plays-nice-with-include/
Posted by Randy
on March 13, 2009
While you can achieve the same functionality using sprintf, this may provide a cleaner approach and one that you are more familiar with. This will allow you to build a string the same way you can use ActiveRecord and the :conditions option.
Basically how this works is by overriding the Array class and adding a method to merge the string and values together into unified string! Enough talk, lets see some code:
class Array
def merge
statement, *values = self
expected = statement.count("?")
provided = values.size
raise "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" unless expected.eql?(provided)
bound = values.dup
statement.gsub("?") { bound.shift }
end
end
As you can see, if you do not provide the right number of values for the statement, it will raise and error. Here is how you would use it:
puts ['Hello ?, how are you', 'John'].merge
#=> Hello John, how are you
Likewise, you can use variables to hold values:
message = "Hello ?, how are you"
name = 'John'
puts [message, name].merge
#=> Hello John, how are you
This will also work with multiple values:
puts ['Hello ?, ? and ?, how are you', 'John', 'Joe', 'Jim'].merge
#=> Hello John, Joe, and Jim, how are you
The only downside to this currently is that you cannot use a ? in the string you are merging, as it will think its a binding character.
Posted by Randy
on January 14, 2009
So since my site, jamzee.com has been in production for over a year now, I have gotten ambitious and decided to do some database maintenance. The first thing I did was log into the server and run a:
mysqlcheck -o database -u username -p
This runs a bunch of mysql tasks; repair, optimize, etc. I notice this was taking a long time on one of the tables which happened to be the sessions table. I got suspicious and logged into the database for a peak.
What did I find, LOTS AND LOTS of rows, 150k+. This seemed relatively unnecessary so after some research found out that I can run the following:
After some time of running that, we have a nice clear, and smaller database now! Next task is to throw that on a cron, probably run on a weekly interval.
Moral of the story, CLEAR THOSE SESSIONS!
Posted by Randy
on October 29, 2008
If you ever have to do multiple actions with activerecord, you should group it into a transaction like so:
Post.transaction do
posts.each do |post|
post = Post.new(:body=>'Whatever')
post.save!
end
end
This will rollback too if the save fails.
Posted by Randy
on October 23, 2008
Here is a cool way you can update columns in a table without writing any SQL using ActiveRecord. Suppose you have a form with checkboxes that are for deleting posts for the ones that are checked:
<input type="checkbox" name="posts[]" value="<%= post.id %>">
Now you can update this in the method of your controller that this form posts to:
Post.update_all({:removed=>true}, {:id=>params[:posts]})
ActiveRecord will take of the fact that you want to update 1 record or multiple!
Posted by Randy
on October 22, 2008
The other day I had to display the number of children items an object had so I decided to do the following:
# Controller
@customers = Customer.find(:all, :include=>[:receive_payments])
#View
<%= customer.receive_payments.count %>
While this worked for what I needed, it executed the following sql every iteration:
SELECT count(*) AS count_all FROM "receive_payments" WHERE ("receive_payments".customer_ref_list_id = E'850000-1071531366')
I thought this wasn’t right considering I used an association, however when you use count, it forces the use of count(*) on the database. This is where size comes in!!!!
<%= customer.receive_payments.size %>
Now we get the same results without the extra database counts!
Posted by Randy
on September 04, 2008
The guys over at NeverBlock have released a database adapter for Rails application that will severely increase the performance of ActiveRecord. Its also really easy to integrate into your application. Heres how:
Add a line to environment.rb for mongrel or thin servers:
require 'never_block/servers/thin'
or
require 'never_block/servers/mongrel'
Change the adapter in database.yml:
adapter: neverblock_postgresql
or
adapter: neverblock_mysql
You can also specify the number of connections (default of 4):
More information, along with benchmarks, can be found here.
Posted by Randy
on August 29, 2008
I’m sure you all know how to use the :conditions attribute when using ActiveRecord:
User.find(:all, :conditions=>['active = ?', true])
And you may even use associations this way:
User.find(:all, :include=>[:photos], :conditions=>['photos.removed = ? and users.active = ?', false, true])
But did you know that you can do this easier through hashes?
User.find(:all, :conditions=>{:active=>true})
User.find(:all, :include=>[:photos], :conditions=>{'photos.removed'=>false, 'users.active'=>true})
Nothing special there, but I thought it was pretty cool. One thing you have to remember when using associations, is to include that model.