4

The app I'm working on makes heavy use of Rails services. My problem is I need to get the root url of the app, similar to how you would use root_url in a view, but this doesn't work in a service. Does anyone know a way to do this other than entering the url in each of my environment setting files?

Edit

I tried using Rails.application.routes.url_helpers.root_url as it suggests to do here stackoverflow.com/a/5456103/772309 but it expects you to pass the :host => ... in as a parameter. That's what Im trying to find.

Ryan Grush
  • 2,076
  • 3
  • 37
  • 64
  • 1
    Possible duplicate of [Can Rails Routing Helpers (i.e. mymodel\_path(model)) be Used in Models?](http://stackoverflow.com/questions/341143/can-rails-routing-helpers-i-e-mymodel-pathmodel-be-used-in-models) – Dave Schweisguth May 09 '16 at 17:51
  • @DaveSchweisguth I tried using `Rails.application.routes.url_helpers.root_url` as it suggests to do here http://stackoverflow.com/a/5456103/772309 but it expects you to pass the `:host => ...` in as a parameter. That's what Im trying to find. – Ryan Grush May 09 '16 at 17:56
  • http://stackoverflow.com/questions/7154914/how-to-get-host-name-in-rails-3 might help there. – Dave Schweisguth May 09 '16 at 18:05
  • @DaveSchweisguth I tried that but I'm having the same problem as the first commenter - "I tried your easy solution on my local machine and it returns my machine's name while I'd like to get 'localhost:3000'" – Ryan Grush May 09 '16 at 18:20
  • How about this answer? http://stackoverflow.com/a/17574412/634576 – Dave Schweisguth May 09 '16 at 18:24
  • @DaveSchweisguth I got a `undefined local variable or method request` error since a Rails service doesn't receive an http request like a controller normally would. – Ryan Grush May 09 '16 at 18:32
  • Presumably your service is used in a controller action. The idea is to save the host:port in `ActionMailer::Base.default_url_options[:host]` in the controller, then retrieve it from there in your service. – Dave Schweisguth May 09 '16 at 18:36
  • @DaveSchweisguth This should work but I think I'm going to just set it in my environment settings. There's a good chance I'm going to need it somewhere else down the road. Thanks for your help though! – Ryan Grush May 09 '16 at 18:44

2 Answers2

3

Based on what I've read from the linked 'Rails services' article, the services are just plain old ruby objects. If that's the case, then you'd need to pass the root_url from the controller to the initializer of your service object. To extend the example from that article:

UsersController

class UsersController < ActionController::Base
  ...
  private
  ...

  def register_with_credit_card_service
    CreditCardService.new({
      card: params[:stripe_token],
      email: params[:user][:email],
      root_url: root_url
    }).create_customer
  end
end

CreditCardService

class CreditCardService
  def initialize(params)
    ...
    @root_url = params[:root_url]
  end
end

EDIT: Alternative solution that leverages the Rails.application.config

class UsersController < ActionController::Base
  before_filter :set_root_url

  def set_root_url
    Rails.application.config.root_url = root_url
  end
end

class CreditCardService
  def some_method
    callback_url = "#{Rails.application.config.root_url}/my_callback"
  end
end
Doug Miller
  • 1,017
  • 2
  • 7
  • 19
  • That's definitely one way to do it, and yes services are just plain ruby objects. The problem with my current use case is that I would have to pass it through multiple services and to a separate server and back, obviously not the most elegant solution. Your answer would work best for most cases however. – Ryan Grush May 09 '16 at 19:36
  • 1
    Understood, then take a look at the edit that I included. I used the UserController again because that was the original example from the article. I typically start with an ApplicationController and have all of my other controllers extend it. I would add the before_filter there that will set the config.root_url for all routes. – Doug Miller May 10 '16 at 04:34
0

Since you're opposed to putting it in your environment folders you could do something like below in your App controller

class ApplicationController < ActionController::Base
  def default_url_options
    if Rails.env.production?
      {:host => "myproduction.com"}
    else  
      {}
    end
  end
end
bkunzi01
  • 4,504
  • 1
  • 18
  • 25
  • I'm not opposed to putting it in my environments folder, was just hoping there was a native Rails method I could call to get the hostname. Its looking like my environment settings is the way to go. – Ryan Grush May 09 '16 at 18:18