Hi,
following the discussion about acts_as_ferret on the Rails mailinglist,
there was an issue about transactions, which could result in beind the
database and ferret out of sync. I have taken a different approach from
acts_as_ferret trying to resolve the transaction problem. Instead of adding
things to the ferret index in the model, I have added it in the controller.
I have only the create part for now and it''s very rough, but it works.
  def create
      if request.get?
      redirect_to :action => ''new''
    else
      @user = User.find(session[:user_id])
      @ad = Ad.new(params[:ad])
      @listing = Listing.new(params[:listing])
      @listing.listing_type = "ads"
      index ||= Index::Index.new(:key => [:id, :table],
                                        :path =>
"#{RAILS_ROOT}/db/index.test",
                                       :auto_flush => true)
      begin
        Listing.transaction(@ad) do
          @ad.listings << @listing
          if @ad.save
            session[:last_addition] = @ad.id
            #ferret create a new entry in the index
            doc = Ferret::Document::Document.new
            doc << Ferret::Document::Field.new("id", @ad.id,
Document::Field::Store::YES,  Document::Field::Index::UNTOKENIZED)
            doc << Ferret::Document::Field.new("table", @
listing.listing_type, Document::Field::Store::YES,
Document::Field::Index::UNTOKENIZED)
            doc << Ferret::Document::Field.new("content",
@ad.title + " " +
@ad.text,  Document::Field::Store::NO, Document::Field::Index::TOKENIZED)
            index << doc
            index.flush
            flash[:notice] = ''Ad was successfully created.''
            redirect_to :action => ''list''
          else
            index.close
            render :action => ''new''
          end
        end
      rescue
        if session[:last_addition]
          logger.error "We verwijderen ad met id:
#{session[:last_addition]}"
          index.query_delete("+id:#{session[:last_addition]}
+table:ads")
          index.flush
          session[:last_addition] = nil
        end
        flash[:notice] = ''An error occurred.''
        redirect_to :action => ''new''
      end
    end
  end
How does it work, or at least how do I think it works. If everything goes
well, the entry gets in the Ferret index. I had to use index.flush, because
without I got a lock. Don''t know why this happens, because I set
autoflush
to true.
When I have a validation error (field of form is empty, or...) in my model,
the else part of @ad.save is taken, there I close the index. I don''t
know if
this is necessary, but just to be sure.
When their is another error: ferret index is not available, trying to add
wrong field or something. Transaction - rescue kicks in. If there are no
validation errors, the ad should get saved, so I set a session variable
last_addition to hold the id of the ad that is being saved, when an error
occurs I have the id of the ad just added. In the rescue block I check if
the session variable last_addition is set. If it is, I search ferret and
delete the addition, afterwhich I flush index (had to add it, otherwise I
would get a lock).
Is my solution waterproof or am I missing something. All feedback is
welcome.
Kind regards,
Nick
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
http://rubyforge.org/pipermail/ferret-talk/attachments/20051221/6bf4535a/attachment.htm