Nov
26
2009

Externalinterface not working in Firefox but working in IE for invisible swf

Yes … as unrealistic as it may sound, yesterday, I ran into an issue where something worked in Internet explorer but not in Firefox. I was trying to call an actionscript functions on a swf file from javascript. This is a fairly standard thing and is well documented on the web. I followed all the steps (registering a callback and embedding the swf using swfobject library) and it worked perfectly in IE. I could call my actionscript functions using javascript in IE but in firefox it would occasionally fail and I would see the following two messages in firebug

uncaught exception: [Exception... "Failure" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: http://localhost:9001/javascripts/swfobject.js?1259133537 :: anonymous :: line 4" data: no]

$(’movieName’).asFunc() undefined method

where movieName is the id of the swf file and asFunc is the function defined in actionscript using ExternalInterface.addCallback. After a lot of googling, I ran into this thread which explained the basic problem. Since my swf file was hidden in the footer of the page, the callbacks worked after I had once scrolled down and seen the footer. Yes as crazy as it sounds, that was really the problem.  Firefox wants you to see the swf once before you make the function call.  To make sure that the 1×1 sized swf file was always visible no matter where you are in the page, I added the following css rule

#movieName {
position: fixed;
top: 0;
left: 0;
}

This rule makes sure that no matter how much you scroll up or scroll down, the swf file is always at the same place (in this case, just at the starting of the page, relative to the browser window). You can read more about fixed positioning here. I am sure there must be a better explanation/solution for this problem but I have tried my approach and it atleast works. If you find a better solution, please post as a comment and I will update the post.

Nov
14
2009

Resizing existing images uploaded using file_column

File column is a great plugin by Sebastian Kanthak for uploading images (and other files) in a rails’ site. The plugin has rmagick integration and can create thumbnails automatically for you. We use it for Muziboo and have been pretty happy with it (yes despite the rmagick dependency). We recently had to update the thumbnail dimensions for a few of our models. Its fairly simple to change the thumbnail sizes in the model and all new uploads are resized to new dimensions. However, the existing images are not automatically changed for you . Thankfully, on digging deeper into the code I found that there is pretty simple way to accomplish that. Lets say you have a user model (with a file_column field photo) and you want to update the thumbnails for all existing images. You just need to simply run the following commands

User.find(:all,:conditions => "photo IS NOT NULL").each do |u|
  u.photo = File.open(u.photo)
  u.save
end

Ofcourse if you have a lot of users, you may wanna fetch them in batches. Also image resizing is a pretty CPU intensive operation so you may wanna watch out for that. Once the operation is over, you will have updated thumbnails for all your previously uploaded images.

Sep
17
2009

Authentication error while fetching gmail contacts using blackbook

Blackbook gem can be used to fetch contacts from gmail, yahoo and hotmail address books. However I recently found out that it would throw up a ‘Must be authenticated to access contacts’ error everytime I tried to import gmail contacts. On digging deeper, I found out that google has changed the contents of its cookie and blackbook uses this cookie to make sure that the user is authenticated. To fix the issue, you just need to make a one line change in the function scrape_contacts in the file lib/blackbook/importer/gmail.rb.

Change

unless agent.cookies.find{|c| c.name == 'GAUSR'  &&
  c.value == "mail:#{options[:username]}"}
raise( Blackbook::BadCredentialsError, "Must be authenticated to access contacts." )

to

unless agent.cookies.find{|c| c.name == 'GAUSR' &&
  (c.value =~ /mail.*:#{options[:username]}/)!=nil}
raise( Blackbook::BadCredentialsError, "Must be authenticated to access contacts." )

If you want to install the updated gem instead of making the change, you can find it in my blackbook fork. My fork also includes the myspace address book import

Sep
08
2009

Query Reviewer & Log4r

I recently found a very neat plugin called Query Reviewer for visualizing slow sql queries in your rails app. When I installed it, I saw this error message

NoMethodError: undefined method `silencefor #<Log4r::Logger:0×39593f8>

You will see this error if you are using log4r for logging instead of the default rails logger. This ticket also talks of the same error in a different scenario. To fix the issue, edit the file vendor/plugins/query_reviewer/lib/query_reviewer/mysql_adapter_extensions.rb and replace all instance of @logger.silence with ActiveRecord::Base.silence.

Jul
02
2009

Myspace email address book import in Ruby

Blackbook gem is the easiest way to add address book import functionality in your webapp. It currently supports Gmail, Yahoo, Hotmail, AOL and CSV import.  I recently patched the gem to add myspace address book import functionality and have checkedin the code on github. I also fixed the name import for gmail. You can find the patched blackbook gem with myspace import functionality here. Since myspace uses email address for login, its not possible to get the blackbook source (myspace) using the username. To import the myspace addressbook, you therefore need to do this

contacts = Blackbook::get 'myspace', :username=&gt;'funkydude@coolemail.com', :password=&gt;'myspace_password'

I have tested the code and its currently in use in Muziboo. If you run into any issues, let me know and I try to fix them. Once the code is stable enough, I will send a pull request to the maintainers of the project.

May
14
2009

Thinking sphinx and paginating find

I wrote sometime back about moving from ferret to sphinx and decided to write the second part of the post today. At Muziboo, we use the paginating find plugin to paginate results. You can find a great tutorial on paginating find at Ilya’s blog. Thinking sphinx however works only with will paginate plugin (atleast out of the box) and needs to be patched to work with paginating_find.

Fortunately, the change is very simple. You need to edit the file lib/thinking_sphinx/collection.rb and comment out the existing code in the function self.create_from_results and add stuff for paginating find. In the end this is how the function looks

26
27
28
29
30
31
32
33
34
35
   def self.create_from_results(results, page, limit, options)
#      collection = self.new(page, limit,
#        results[:total] || 0, results[:total_found] || 0
#      )
#      collection.results = results
#      Changing the stuff to work with paginating find
      PagingEnumerator.new(options[:per_page] || 20, results[:total_found] || 0, false, options[:page], 1) do |page|
        instances_from_matches(results[:matches], options)
      end      
    end

Make the change and restart your mongrel and you are ready to go!

May
06
2009

Rails 2.3 routing gotcha with :format

I recently upgraded Muziboo to Rails 2.3 and found out that some of my routes were broken. On digging deeper I found out that I had some routes with two version, one without :format and one with :format going to different controllers/actions. I had the route with :format before the route without :format in the routes.rb file and changing the order fixed the problem. I am not sure why this happened but its been working fine since the change. If you run into routing issues, do try this and let me know if it worked for you.

May
04
2009

Use RedCloth to nofollow all user generated links

Nofollow attribute in link tag makes sure that search engine bots don’t use the link for crawling the destination site. This is a measure to combat link spam and to make sure that you don’t pass link juice if you don’t want to. This is especially important for user generated content sites as they have no control over what links the users will put.

At Muziboo, we use RedCloth to format the text that users input. We also use it to filter out any css styling the users put in and some html tags like embed, img etc. Let me show you how we nofollow all links automatically. Create a file called redcloth extension.rb and put it in config/initializers directory. Now put this in the file (please replace a_tag below with a. I had to stop wp from making that line a link)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
module RedCloth::Formatters::HTML
  include RedCloth::Formatters::Base
 
    def link(opts)
     "<a href=\"#{escape_attribute opts[:href]}\"#{pba(opts)} rel=\"nofollow\">#{opts[:name]}</a>"
 
    end
 
    private
 
    # HTML cleansing stuff
    ALLOWED_TAGS = {
      'a' =&gt; ['href', 'title'],
      'br' =&gt; [],
      'i' =&gt; nil,
      'u' =&gt; nil,
      'b' =&gt; nil,
      'pre' =&gt; nil,
      'kbd' =&gt; nil,
      'code' =&gt; ['lang'],
      'cite' =&gt; nil,
      'strong' =&gt; nil,
      'em' =&gt; nil,
      'ins' =&gt; nil,
      'sup' =&gt; nil,
      'sub' =&gt; nil,
      'del' =&gt; nil,
      'table' =&gt; nil,
      'tr' =&gt; nil,
      'td' =&gt; ['colspan', 'rowspan'],
      'th' =&gt; nil,
      'ol' =&gt; ['start'],
      'ul' =&gt; nil,
      'li' =&gt; nil,
      'p' =&gt; nil,
  }
 
    def clean_html( text, tags = ALLOWED_TAGS )
        text.gsub!( /<!--\[CDATA\[/, '' )
        text.gsub!( /<(\/*)(\w+)([^-->]*)&gt;/ ) do
            raw = $~
            tag = raw[2].downcase
            if tags.has_key? tag
                pcs = [tag]
                pcs &lt;&lt; "rel=\"nofollow\"" if (tag == 'a' and raw[1]=='')
                tags[tag].each do |prop|
                    ['"', "'", ''].each do |q|
                        q2 = ( q != '' ? q : '\s' )
                        if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i
                            attrv = $1
                            next if prop == 'src' and attrv =~ %r{^(?!http)\w+:}
                            pcs &lt;&lt; "#{prop}=\"#{$1.gsub('"', '\\"')}\"" unless $1.nil?
                            break
                        end
                    end
                end if tags[tag]
                "&lt;#{raw[1]}#{pcs.join " "}&gt;"
            else
                " "
            end
        end
    end
 
end

To filter the input, simply call RedCloth.new(input_text,[:sanitize_html,:filter_styles]).

These instructions are for Rails 2.3.2. For older rails’ put the redcloth_extensions.rb file in lib folder and require it in your environment.rb

Apr
22
2009

Javascript and CSS debugging on internet explorer

It comes as no surprise that when it comes to Javascript, browsers such as Firefox and Safari are more forgiving than Internet Explorer. Also tools like Firebug make javascript debugging very simple. However firebug (just like firefox) does not seem to mind issues like an extra comma or a missing semilcolon and this makes everything break on ie. I recently ran into one such bugs and had a big javascript file that had an error somewhere and resulted in exptected string, identifier error on ie. While looking for javascript debugging tool for ie, I found a few tools

Internet Explorer Developer Toolbar

Microsoft Script Debugger

You can find some more information about these tools at this msdn blogpost. However, the tool that eventually helped me fix the error and which is much more generic and useful is JSLint. Written by Douglas Crockford, this tells you not only about the errors in your javascript file but also bad coding practices that can be seen in your code. I fixed all errors listed on JSLint for my js file and all errors disappered in ie. If you are into writing javascript (for ie or firefox), do validate your code with this tool.

Mar
21
2009

Ferret to Sphinx: Part 1 – Why and how to integrate it with acts_as_taggable

I am currently working on moving Muziboo’s search from ferret to sphinx. We were using acts_as_ferret (AAF) plugin which provides a very simple rails integration with ferret. AAF binds itself to the active record callbacks and makes index updation painless. However AAF is pretty unstable in production mode and we realized this only lately with increasing traffic. We often had corrupted indexes and page errors as a result of that (since ferret is almost deeply integrated into models, it breaks a lot of functionality apart from search when something goes wrong). Also another problem with ferret is the high memory usage and the fact that with multiple mongrels, you will have to run a drb process to make sure the index is not written by multiple processes and corrupted.

On looking for alternatives, I found out about Thinking Sphinx, a plugin that makes it easy to use sphinx in your rails project. There is some documentation to get you started with TS once you decide to use it and also a peepcode pdf which has some good info. I could get the basic search functionality up and running in no time but had to spend sometime getting some integration going with other plugins. I will detail some of those things in this and next few posts.

Acts as taggable helps you in tagging your objects and we wanted sphinx to search on the tags too. It turns out that its very simple. All you have to say in your define_index block is

1
indexes taggings.tag.name:as=>tag_name

Just make sure that you restart sphinx and reindex your data before after adding this in your model(s).

 
Powered by Wordpress and MySQL. Theme by openark.org