Search code examples
ruby-on-railsrescue

How to rescue from bad url


I have a method in my application that finds a photo from the og:image tag of a link that is submitted. In my create action, I use the method photo_form_url, described below.

def photo_from_url(url)
  if !Nokogiri::HTML(open(url)).css("meta[property='og:image']").blank?
    photo_url = Nokogiri::HTML(open(url)).css("meta[property='og:image']").first.attributes["content"]
    self.photo = URI.parse(photo_url)
    self.save
  end 
end

However, this produces an error if a bad url is entered. I tried to rescue as below, but this gives me an "undefined method redirect_to"

def photo_from_url(url)
  begin
    if !Nokogiri::HTML(open(url)).css("meta[property='og:image']").blank?
      photo_url = Nokogiri::HTML(open(url)).css("meta[property='og:image']").first.attributes["content"]
      self.photo = URI.parse(photo_url)
      self.save
    end
  rescue OpenURI::HTTPError
    redirect_to :back, notice: 'link's broken!'
  end
end

What am I doing wrong?


Solution

  • According to your answer to my comment, your function photo_from_url is defined in the model. Trying to redirect a user within a model is not possible as shown by the error you are facing.

    Bear in mind that your model can be called outside of a browsing session environment. EG:

    • tests
    • rake task

    You should thus never, ever put any code that has to do with manipulating the user browser, or the user session within your models. This is the job of the controller.

    So what you need to do is simply raise an exception or return a specific value in your model when you are encountering a bad url. And react to that exception / return value in your controller by redirecting the user. This ensure that anything that has to do with the user browser stays in the controller, and that you could implement a different behavior in a rake task if encountering the same error.

    So, your model should do stuff, and raise errors when it can't :

    # Link.rb
    def photo_from_url(url)
      if !Nokogiri::HTML(open(url)).css("meta[property='og:image']").blank?
        photo_url = Nokogiri::HTML(open(url)).css("meta[property='og:image']").first.attributes["content"]
        self.photo = URI.parse(photo_url)
        self.save
      end 
    end
    

    Your controller should ask your model to do stuff, and deal with the user if there is a problem :

    # link_controller
    # in create
    begin
      link.photo_from_url(url)
    rescue OpenURI::HTTPError
       redirect_to :back, notice: 'link's broken!'
    end