7

My webapp needs to encrypt its session data. What I setup is:

config/initializers/encryptor.rb:

require 'openssl'
require 'myapp/encryptor'

MyApp::Encryptor.config[ :random_key ] = OpenSSL::Random.random_bytes( 128 )
Session.delete_all

app/models/session.rb:

require 'attr_encrypted'

class Session < ActiveRecord::Base
  attr_accessible :session_id, :data
  attr_encryptor :data, :key => proc { MyApp::Encryptor.config[ :random_key ] }, :marshal => true

  # Rest of model stuff
end

That all works great, and keeps the session data secured. Here's the problem: when I run my custom rake tasks it loads the initializer and clears all the sessions. Not good!

What can I put in my initializer to make sure it ONLY runs for the webapp initialization? Or, what can I put in my initializer to make it NOT run for rake tasks?

Update: OK, what I've done for the moment is add MYAPP_IN_RAKE = true unless defined? MYAPP_IN_RAKE to my .rake file. And then in my initializer I do:

unless defined?( MYAPP_IN_RAKE ) && MYAPP_IN_RAKE
    # Web only initialization
end

Seems to work. But I'm open to other suggestions.

sbutler
  • 617
  • 5
  • 10
  • This seems liable to bite you in other ways in the future. Any time the server is restarted, you're going to lose all your sessions (which seems to be the intended behavior), but that includes the server getting autokilled by using too much memory, having a request run too long, etc. – Michael Fairley Sep 22 '11 at 02:44
  • I understand the downsides, but I think it is worth it. App being restarted resetting sessions: acceptable. Too much memory or too long of a request? Under unicorn these situations should only happen in a worker process. And since I set `preload_app = true` the initialization only happens in the master. So unicorn can respawn workers without causing a re-initialization. – sbutler Sep 22 '11 at 03:45
  • Possible duplicate of [Rails 3 initializers that run only on \`rails server\` and not \`rails generate\`, etc](http://stackoverflow.com/questions/8660019/rails-3-initializers-that-run-only-on-rails-server-and-not-rails-generate-e) – davmac Feb 17 '17 at 12:06

2 Answers2

9

You might make a modification to your application in `config/application.rb' like this:

module MyApp
  def self.rake?
    !!@rake
  end

  def self.rake=(value)
    @rake = !!value
  end

Then in your Rakefile you'd add this:

MyApp.rake = true

It's nice to use methods rather than constants since sometimes you'd prefer to change or redefine them later. Plus, they don't pollute the root namespace.

Here's a sample config/initializers/rake_environment_test.rb script:

if (MyApp.rake?)
  puts "In rake"
else
  puts "Not in rake"
end

The programmable nature of the Rakefile affords you significant flexibility.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • OK, I like this. I've changed the setter to `@rake = !!value unless defined? @rake` to make sure it's only set once. Then I also added to environment.rb `MyApp.rake = false`. Sound reasonable? – sbutler Sep 22 '11 at 03:41
  • Why would you worry about setting it only once? A better practice than simply ignoring the duplicate set is to at least emit a warning, or better, to throw an exception so you can track down the source of the problem. – tadman Sep 22 '11 at 14:35
  • I guess I'm concerned that while running as webapp code somehow the Rakefile will get loaded. I'm thinking symmetrically: as rake, the webapp environment is loaded, so I should also handle the case where as the webapp, rake gets loaded. – sbutler Sep 22 '11 at 16:45
  • If you load your `Rakefile` from inside your app, you are doing something *very* peculiar. I don't think that even works. – tadman Sep 22 '11 at 17:28
  • Thanks, i was looking for this. It feels a little hacky, is this the only way to achieve this? – JavierIEH Oct 30 '11 at 23:45
  • If by "hacky" you mean "not a standard use case" then yes, it is. – tadman Oct 31 '11 at 14:37
2

There is another work around:

unless ENV["RAILS_ENV"].nil? || ENV["RAILS_ENV"] == 'test'

When you launch with rake your ENV["RAILS_ENV"] will be nil. The test for 'test' is to avoid to run when using rspec.

I know that is reckon to use Rails.env but it return "development" when it is not initialised.

http://apidock.com/rails/Rails/env/class

# File railties/lib/rails.rb, line 55
def env
  @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] 
     || ENV["RACK_ENV"] || "development")
end
tolbard
  • 1,273
  • 15
  • 20