简体   繁体   中英

What is the best way of accessing routes in ActiveRecord models and observers

I have a situation where I want to make a request to third-party API(url shortening service) after creating a record in the database (updates a column in the table which stores the short url), in order to decouple the API request from the Model, I have set up an ActiveRecord Observer which kicks in every time a record is created, using after_create callback hook, here is the relevant code:

class Article < ActiveRecord::Base
  has_many :comments
end

class ArticleObserver < ActiveRecord::Observer
  def after_create(model)
    url = article_url(model)
    # Make api request...
  end
end

The problem in the above code is article_url because Rails Routes are not available in either Model or ModelObservers, same as ActionMailer (similar problem exists in Mails where if we need to put an URL we have to configure "ActionMailer::default_options_url"). In theory accessing routes/request object in Model is considered a bad design. To circumvent the above issue I could include the url_helpers module as described in the following URL:

http://slaive-prog.tumblr.com/post/7618787555/using-routes-in-your-model-in-rails-3-0-x

But this does not seem to me a clean solution, does anybody have a pointer on this issue or any advice on how it should be done?

Thanks in advance.

I would definitely not let your models know about your routes. Instead, add something like attr_accessor :unshortened_url on your Article class. Set that field in your controller, and then use it from your observer. This has the added benefit of continuing to work if you later decide to set your shortened URL asynchronously via a background task.

Edit

A couple of things, first of all.

  1. Let's get the knowledge of creating a short_url out of the model entirely.
  2. We could nitpick and say that the short_url itself doesn't belong in the model at all, but to remain practical let's leave it in there.

So let's move the trigger of this soon-to-be-background task into the controller.

class ArticlesController < ApplicationController
  after_filter :short_url_job, :only => [:create]

  # ...


  protected

  def short_url_job
    begin
      @article.short_url = "I have a short URL"
      @article.save!
    rescue Exception => e
      # Log thy exception here
    end
  end
end

Now, obviously, this version of short_url_job is stupid, but it illustrates the point. You could trigger a DelayedJob , some sort of resque task, or whatever at this point, and your controller will carry on from here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM