Rails Autocomplete Tag List

I wanted to make an autocomplete text field on a edit form that listed all of the tags that are already entered in the system. It is quite simple, but I thought I would share it to save some time for someone. Of course we are using acts_as_taggable

The controller :

def auto_complete_for_tag_name
  auto_complete_responder_for_tag_name params[:tag][:name]
end

def auto_complete_responder_for_tag_name(value)
  @tag_list = Tag.find(:all,
  :conditions => [ ‘LOWER(name) LIKE ?’,
  ‘%’ + value.downcase + ‘%’ ],
  :order => ‘name ASC’,
  :limit => 10)

  render :partial => ‘tags’

end

def edit
  @content = Content.find(params[:id])
  @tag = Tag.new
  @tag.name = @content.tag_list
end

To retrieve the current tag list you need to make a new Tag object and add the tag list to it.

In my _tag.rhtml partial :


<ul class=”tags”>
  <% for tag in @tag_list do -%>
    <li class=”contact”><div class=”name”><%=h tag.name %> </div></li>
  <% end -%>
</ul>

In My _form.rhtml


<p>Tags (Seperate with space)<br/>

<%= text_field_with_auto_complete :tag, :name,
{:size =>50, :skip_style => true},
{:indicator =>’searchIndicator’,
:tokens => [’ ‘, ‘\n’]} %>
<%= image_tag(”/images/indicator2.gif”, :id => ’searchIndicator’, :style => ‘display:none;’) %>
</p>

You will notice that I have added a search indicator, which you will need to have on your system.

Thats how easy it is :)

Hamza

RailsConf, My thoughts

I have just got home from two very exciting days at the rubyconf conference in London. Here are a few observations and just a few things I have learnt.

Observations I am not sure why, but I had a distinct impression that the majority of attendees would have been from Europe. However I seemed to come across people from the US or Canada. People who have come over from the states especially for the conference or people who are making it part of their vacation. Not that this is a bad thing. In fact it showed me that they were really committed to Rails and to Ruby. I have to say if my company was not paying for my ticket, I would never have dreamed of going to the conference. Maybe I need to get more involved :)

As this is my first conference, I was not sure what to expect. It was an entire new experience. I was pleasantly surprised by the organisation of the conference by skillsmatter and also by the excellent calibre of the speakers. As I am new to the ruby world, I did not know the speakers (apart from David H), this conference allowed me to put faces and personalities to these very influential people within the Rails / Ruby community.

I got to see the Rails core team. This was a real eye opener for me, as I had no idea who they were or what their thoughts were for the future of Rails (I know I should read more).

Then comes David H’s talk. I have to say that I was impressed with David’s ideas and the way he presented himself. I really like the RESTFUL stuff and ActiveResource and also the Simply Helper. For those of you that don’t know, this is a way of putting conventions into the view layer like he has just done for the controller using REST.

Things I learned

Overall I have to say that I did learn allot (especially about Ruby)

  • Rails 1.2 is to be released very soon and is going to depreciate a whole bunch of methods.
  • In Rails 2.0 these deprecated methods will be removed.
  • 1.2 is going to heavily push the REST stuff.
  • Routing has completely been rewritten as it was a bottleneck. This is to be released in 1.2
  • The goals of ActiveResource, It is not going to ship with Rails 1.2, maybe 2.0 ?
  • With all the restful work on the controllers, the view started to look dated, so they have developed SimplyHelper, which is a convention for views.
  • Rails speaks ‘C’ – This was a talk I attended. I think things like this are very important. If we have a very complex algorithm or we have some legacy C systems, we need to be able to call C code from Ruby. In the Python CMS world Zope does this for a lot of complex operations (as far as I remember, correct me if I am wrong). 4 different approaches were mentioned. I noted that SWIG seemed to be one of the better options (and it supports c++).
  • If you are using C to do a big CPU intensive task, or a task that will take a while to complete, then you need to use BackgroundDRB. This allows you to spawn requests in the background (surprise,surprise). So in a web app the client gets a response straight away, so he knows something is happening , a progress bar would be a good indicator in this situation.
  • I really enjoyed the talk about high performance. I always wondered if anyone had deployed Rails apps, which had to handle over a million hits per day. Well James Cox seemed to have allot of experience in this field, and he shared some tips with us. I will mention a few here.
    • Speed Perceived – This is to use Ajax to make the app perceive fast to the user. The user will not know.
    • Always use :select, :limit and :offset in your queries.
    • Try and use lazy loading (:include).
    • MEMCACHED – Basically always use this as much as possible, he really emphasised this point.
    • Avoid shared hosting (obvious).
    • Page Caching – BAD – Avoid this as it is a nightmare to clean up.
    • Fragment Caching – Is better then page caching, but their are scalability issues
    • 8 server Gem (server architecture) – 2 x Proxy / Web static servers, 4 x Application servers, 2x Database servers with database replication.
    • Session management – use memcache, not the database store
    • If you have one server use Apache (fcgi), but this does not scale well, so for multiple machines use mongrel.
    • Put Google Analytics in its own iframe, this will avoid your app waiting to show the page because it is retrieving the js from google.
  • Django
    • Really cool!
    • Has built in user and groups in the framework
    • Uses python code to define database schema. This allows them to add rich data models. So you can define an upload field or a url field, the system will automatically know what to do with this field. This allows them to auto generate the admin interface to such a high level and what streamlined is trying to replicate for Rails.
    • Reusable template views with hierarchy functionality.
    • Try and not use AJAX in the admin section, as you do not know what kind of PC your publishers are going to publish from (old, etc.)

Please comment if you found this useful or not. Hamza

RailsConf

I am really excited that I am going to RailsConf in London! Its going to be my first tech conference :)

Hopefully I can write some thoughts about it on this blog.

Hamza

Delicious with Ruby on Rails - JSON

I recently (well about a month ago!) read a very good post that informs you how to add your delicious links to your rails app.

I was using that method and all was well, until I got a request that the links should open in a new window. With the simple html access to my links, that was not an option you can pass. So I had to resort to using something more complicated; JSON seemed the easiest for me to read in and manipulate.

I would advise you to follow this tutorial and then come back here and see how the code can be changed to use JSON instead of the HTML api.

You will need to install the JSON ruby library first.

gem install json

If that does not work just download it from here and run the install script.

Here is the modified method


def delicious_links(limit ="20", aclass="grey")
    begin
      unless read_fragment(:action => 'delicious_links')
        logger.info "Getting new delicious_links" 
        require "open-uri" 
        require 'json'
        @delicious_links = "" 
        link = "http://del.icio.us/feeds/json/YOUR_USERNAME_HERE?raw=true&count="+limit
        @jsonObject = "" 

        open(link) {|f|
          f.each_line {|line| @jsonObject += line }
        }
        @urls = parse(@jsonObject)

        for i in 0...@urls.length
          @url_obj = @urls.fetch(i)
          url ="" 
          title ="" 
          tags ="" 
          @url_obj.each {|key, value|  
           url = value if key == "u" 
           title = value if key == "d" 
           tags = value if key == "t" 
          }
          @delicious_links += "<div class=\"blogSideBarLink\">" + "<a href= \""+url+"\" target=\"blank_\" class=\""+aclass+"\">"+ title+"</a></div>"            
        end
      end
    rescue
      @delicious_links = "Not available @ this time" 
    end
    logger.info "delicious_links finished" 
    render_without_layout
  end

Search problems

In my last post I said that I was using acts_as_ferret. However I was finding it difficult to create an index for a certain section of the site. I think this was due to me having null fields some of the database fields. I could nt change this.

When I was having problems I turned to acts_as_searchable . As the post states the search plugin uses HyperEstraier which is an opensource search engine. It seems to be very good and above all (for me) the UTF support seems excellent. This is demenstroated by having a Japenese language search demo on their site.

I managed to get it to work :) I will post how in the next couple of days.

My first thoughs about HyperEstraier is that it has some very good features, but most of the features I am not going to use in the near future. Overall the set up is a bit more invloved then ferret, this is because you need to run a deamon.

More thoughts soon!

Hamza

acts_as_ferret error

I started using the acts_as_ferret plugin for ruby on rails today. I was having a problem with the site not getting indexed – After putting the acts_as_ferret in the desired models, I searched for words that I knew existed and i was not getting any responses. I figured out that it was not being indexed. if the index directory does not exist than the plugin calls rebuild_index method. This is supposed to go through your database and create the index. The app was failing executing the rebuild_index method. I googled the error and came across this post It was an error because i was using Unicode. So I added the following to my environment.rb file and it has indexed the files :


    ENV[’LANG’] = ‘en_GB.UTF-8′
    ENV[’LC_TIME’] = ‘C’

All I have to do now is figure out how to use ferret :)

Hamza

Small Bug in acts_as_taggable with acts_as_versioned

I have come accross a bug if you are using acts_as_taggable and acts_as_versioned on the same model. For some reason acts_as_taggable triggers a new version to be stored in the version history. So it stores two identical versions every time. As soon as you turn off the tagging it works.

I have tried to get around the issue by using the method version_condition_met? in the model. I thought it worked but if the fields were null or blank it failed.

I will try a few more things and post the results here.

Hamza

acts_as_taggable with different language tags

As part of my Rails project I needed to tag items in Chinese and in English. For obvious reasons I wanted to use the acts_as_taggable plugin (not the gem). I really like the way it works. It is very clean and elegant solution for tagging.

However my problem was how do I distinguish a Chinese tag from an English tag. I came up with a few solutions. One being to use the geotagging formula which would translate to Chinese_tag:English_tag. Initially this seemed like a good idea, But, it does seem a bit tied down. What if a user wanted to tag it with an English tag, but not the corresponding Chinese tag ?

So the simple solution I came up with was to add a language field (VARCHAR) to the tag database. If it was a Chinese tag I would simply put ‘ch’ in the language and if it was English I would simply put ‘en’

Here is the actual change I made to the plugin :


def tag_with(list, lang)
  Tag.transaction do
    taggings.destroy_all
    Tag.parse(list).each do |name|
      if acts_as_taggable_options[:from]
         send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self) 
      else
        begin
          tag_find = Tag.find_by_name_and_language(name,lang).on(self) 
        rescue
          Tag.create(:name => name, :language =>lang).on(self) 
        end
      end 
    end 
  end 
end

As you can see this method takes an extra parameter ‘lang’. The change has been made in the else statement. It tries to find the tag with the language. If that fails then it creates the tag. This replaced a simple Tag.find_or_create_by_name(name).on(self)Its as simple as that. The tag_with method now accepts and saves the language field.

I also implemented these methods which are self explanatory :


 def tag_chinese_list
    tags.collect {|tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name if tag.language =="ch" }.join(" ") }
end

The above method simply retrieves all of the Chinese tags. I have a similar one for English. I also added a find_tagged_with_chinese method. This is just a copy of the original find_tagged_with method with an extra AND language =”ch” at the end.

I should really re-factor the code. For example making the tag_list take a language parameter.

I hope this helps someone.

Hamza

FCKeditor on Rails

Hi again,

I found myself needing a WYSIWYG editor for the rails app I am developing. I thought FCKeditor is great. I installed it by following these instructions

All was well, but I could not get the file upload interface to work under Rails. So I did some searching and came across this project. Michael Moen had got it all to work very nicely.

FCKeditor is fully integrated into my app. Nice!

Hamza

Progress!

Hi,

I have made a lot of progress with Ruby on Rails. I have to say that I have taken a real liking to this framework. I have to applaud the Rails team and community.

As is expected I have come across a few difficulties. But I have always got a answer on the Rails mailing list. Any big software project needs to have such a community to back it up, otherwise new people will never come on the scene.

Hopefully my next post will run through a small tutorial of editing and saving a HTML Form using RJS templates. It is unbelievable easy.

Hamza

Ruby on Rails First Thoughts

Well my head has been in RoR for about 4 days. I have to say I have found it quite difficult to learn. I think that is because I have been relying on tutorials and wiki entries. I think if I would have read the rails book things would be alot easier (but slower ?). I have not got to grips with it fully. I am still trying my best to learn some of the inner workings.

Rails 1.1 was released a couple of days ago. It has a bunch of cool new features. But I am not sure I am at the stage of using half of the features. Nevertheless I have upgraded :) with a little bit of difficulties. This was due the version of Ruby I had was not supported. I had version 1.8.3, put that is not supported and because I was Ubuntu, I found it difficult to update it.

Ruby on Rails

Although you may have gathered I am looking into Python frameworks. I have just been asked at work, if we can use Ruby on Rails as a platform to develop a pilot project we are developing. (I can’t give any details, just to say that it will be a bilingual site :)

So this leaves me with learning two very different frameworks and languages. Such is life. I can say that the documentation for Rails is awesome, compared to TurboGrears. It is going to be an interesting few months …