Domanda

I'm having a weird issue, my app seem to get stuck in a loop.

I have a model called Pages which allows the user to input a URL on save I have a after_save method called process_pages which looks as follows

pages.rb (model)

class Page < ActiveRecord::Base
  require 'open-uri'

  after_save :process_pages

  def process_pages
    self.html = open(self.url).read
    self.save
  end 
end

On saving the URL I can see in the development console that it get the HTML of the site but tries to constantly save the record over and over again stalling the page and I have to manually exit the server.

When I start back up again the record has been added and works as expected until I add another URL?

Is there anything wrong with my code which might be causing this continuous loop?

Thanks for reading!

È stato utile?

Soluzione 3

If you need to call process_pages only once after Creating a Page record and not after Updating a Page record then I would suggest to use after_create instead.

class Page < ActiveRecord::Base
  require 'open-uri'

  after_create :process_pages

  def process_pages
    self.html = open(self.url).read
    self.save
  end 
end

With after_save :process_pages, process_pages method would be called every time you save a Page record. You are saving a Page record again within process_pages method which triggers the after_save callback and you start looping.

See this SO Question for difference between after_save and after_create. You will understand better as to why you are going in loops.

Altri suggerimenti

You are stuck in a loop because your callback is triggered after save, and then the method definition itself is calling save, causing the callback to fire again.

You have some options. You can change the callback to before_save.

class Page < ActiveRecord::Base
  require 'open-uri'

  before_save :process_pages

  def process_pages
    self.html = open(self.url).read
  end 
end

You can change to an after_create callback that only fires once the record is created and not updated, but this may not be desired behaviour.

You can also skip the callbacks by calling update_column instead of calling save as pointed out by @BroiSatse

This is because you are resaving it all the time. Instead do:

def process_pages
  update_column(:html, open(self.url).read)
end

update_column is saving one column to the database skipping all the callbacks, so it won't retrigger your after_save callback. It is however pretty pointless to do two queries while you can do one with before_save filter:

before_save :process_pages

def process_pages
  self.html = open(self.url).read
end 

But probably best way to go with is overriding setter for url method:

def url=(value)
  super
  self.html = open(self.url).read
end

This way you can use page html before the model is saved.

So does self.url point back to the pages url? If so, when you save it, it hits your server for the page, which might cause another save and another url request, etc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top