How can I refactor this oversized Ruby method into smaller bits and have unit tests for them?
Create a model to hold all the logic and call that with parameters and have tests for the model methods:


  Unit Tests


require 'spec_helper'

describe "Prepare Search methods" do

  describe "PrepareSearch#start_date" do

    subject { PrepareSearch.start_date('2000') }
    it { should == DateTime.new(2000,1,1) }

  end 

  describe "PrepareSearch#end_date" do

    subject { PrepareSearch.end_date('2009') }
    it { should == DateTime.new(2009,12,31) }

  end 

  describe "PrepareSearch#groups" do

    subject { PrepareSearch.groups(['1','2','3']) }
    it { should == " and group_id in (-1,1,2,3)" }

  end 

  describe "PrepareSearch#versions" do

    before(:each) do  
      @versions= {:version =&gt; 0, :version_comparison =&gt; '&gt;=', :include_blank_version =&gt; true}
    end 
    subject { PrepareSearch.versions(@versions) } 
    it { should == " and (version_number &gt;= 0.0 or version_number is NULL or version_number = '' )" }

  end 

  describe "PrepareSearch#dates" do

    subject { PrepareSearch.dates(Date.new(2009), Date.new(2012) ) } 
    it { should == " and ((content_date is NULL) or( (content_date &gt;= \"2009-01-01\") and (content_date &lt;= \"2012-01-01\") ) )" }

  end 

  describe "PrepareSearch#basic_search" do

    subject { PrepareSearch.basic_search("test") }
    it { should == ["(url_address LIKE ? or alt_text LIKE ? or version_number LIKE ?)","%test%","%test%","%test%"] }

  end 

  describe "PrepareSearch#text_search" do

    subject { PrepareSearch.text_search("tests","or","rs") }
    it { should == " and ( (url_address LIKE \"%tests%\" or alt_text LIKE \"%tests%\" or version_number LIKE \"%tests%\") or (url_address LIKE \"%rs%\" or alt_text LIKE \"%rs%\" or version_number LIKE \"%rs%\") )" }

  end 

end



  New Model "PrepareSearch"


class PrepareSearch

  def self.start_date(start_year)
    (start_year + '/01/01').to_date
  end 

  def self.end_date(end_year)
    (end_year + '/12/31').to_date
  end 

  def self.groups(groups=[])
    @groups_comparison= ' and group_id in (-1'
    groups.each do |group_id|
      @groups_comparison &lt;&lt; ','+group_id
    end 
    @groups_comparison+= ')' 
  end 

  def self.versions(version_information={} )
    @version = version_information[:version].to_f
    @version_comparison = ' and (version_number ' + version_information[:version_comparison] + ' ' + @version.to_s
    if version_information[:include_blank_version]
      @version_comparison+= " or version_number is NULL or version_number = '' )"
    else
      @version_comparison+= " and version_number is not NULL and version_number &lt;&gt; '' )"
    end 
  end 

  def self.dates(from, to) 
    @from= from
    @to= to
     ' and ((content_date is NULL) or( (content_date &gt;= "' + @from.to_s + '") and (content_date &lt;= "' + @to.to_s + '") ) )'
  end 

  def self.text_search(words_1,comparison_operator='',words_2='')
    @words_1 = words_1
    @words_2 = words_2
    @comparison_operator= comparison_operator
    if @words_2.length &gt; 0 
      @text_search = ' and ( (url_address LIKE "%'+@words_1+'%" or alt_text LIKE "%'+@words_1+'%" or version_number LIKE "%'+@words_1+'%") '
      @text_search+= @comparison_operator
      @text_search+= ' (url_address LIKE "%'+@words_2+'%" or alt_text LIKE "%'+@words_2+'%" or version_number LIKE "%'+@words_2+'%") )'
    else
      ' and (url_address LIKE "%'+@words_1+'%" or alt_text LIKE "%'+@words_1+'%" or version_number LIKE "%'+@words_1+'%")'
    end 
  end 

  def self.basic_search(words)
    @words = words
    @conditions = ['(url_address LIKE ? or alt_text LIKE ? or version_number LIKE ?)', "%"+@words+"%", "%"+@words+"%", "%"+@words+"%"]
  end 

end



  Refactored index action


  def index
    @from = PrepareSearch.start_date(params[:from] ||= '1991')
    @to = PrepareSearch.end_date(params[:to] ||= '2299')

    if params[:search_text_1st_phrase] # both simple and advanced search use this field.
      @words_1 = params[:search_text_1st_phrase]
      if params[:commit].downcase == 'advanced search'
        @join_operator = params[:join_operator].downcase
        @words_2 = params[:search_text_2nd_phrase]
        @text_search = PrepareSearch.text_search(@words_1, @join_operator, @words_2)
        @groups_comparison = PrepareSearch.groups(params[:groups])
        @version_information = { :version =&gt; params[:version], :version_comparison =&gt; params[:version_comparison], :include_blank_version =&gt; params[:include_blank_version] }
        @version_comparison = PrepareSearch.versions(@version_information) 
        @date_comparison = PrepareSearch.dates(@from, @to)
        @conditions = '1=1' + @groups_comparison+ @version_comparison+ @date_comparison + @text_search
      else
        @conditions = PrepareSearch.basic_search(@words_1)
      end 
    else
      @conditions = ''
    end 
    @links = Link.all(:joins =&gt; :group, :include =&gt; :group, :order =&gt; 'groups.group_name, links.position', :conditions =&gt; @conditions)
    session[:full_details] = (params[:full_details] == 'true') ? 'true' : 'false' rescue 'false'
    respond_to do |format|
      format.html
    end 
  end 


Also (next steps):  


Write controller/integration tests to check actual search results for various combinations of parameters.  Needs a bunch of test data.  Probably at least 20 links and 4 groups for useful testing data.  
consider making an object for all the params and passing them to one method call.