Rails, A method to be called only in production - ruby-on-rails-3

I remember seeing this somewhere online but I know have trouble finding information about it. In Rails 3.1, I have a method at the beginning of a session controller, force_ssl, I only want it called in a production environment, how do I do that?
To clarify, the code looks something like this
class SessionsController < ApplicationController
force_ssl
end

I had a similar problem. force_ssl caused problems by testing with capybara and selenium. This here solved my problems and the tests are now running:
force_ssl if Rails.env.production?
I am using the line above in some Controllers. For example in the SessionController and UserController.

Rails.env.production? returns true if the current environment is 'production'. More generally, Rails.env.somestring? returns true if Rails.env == "somestring". From there you should be good.
** EDIT **
Well actually, there's an easier way to use ssl only in production. Check out this article

Related

Getting uninitialized constant (NameError) inside decorators when running rspec tests via rake

In my app I use an engine (blogit) to which I want to add some changes / behaviours.
I followed the guides on how to override engine controllers/models and added the following:
The Code
In config/initializer/blogit.rb
# Requires extension ruby files in lib/blogit.
Dir[Rails.root.join("lib/blogit/*.rb")].each {|f| require f}
In lib/blogit/engine.rb
module Blogit
class Engine < ::Rails::Engine
isolate_namespace Blogit
config.to_prepare do
Dir.glob(Rails.root + "app/decorators/**/blogit/*_decorator*.rb").each do |c|
require_dependency(c)
end
end
end
end
In app/decorators/controllers/blogit/comments_controller_decorator.rb
Blogit::CommentsController.class_eval do
def create
Rails.logger.info "decorated controller action"
# ... overridden stripped ...
end
end
In app/decorators/models/blogit/comment_decorator.rb
Blogit::Comment.class_eval do
belongs_to :user
end
To be mentioned:
I have also created a migration to add a user reference to the comments model, since my app uses devise and I only want logged_in users to be able to comment. (Therefore I don't need the standard behaviour, so I'm going to override it.)
The Problem
If I run rake I get the weird error:
/Users/Kassi/.rvm/rubies/ruby-1.9.3-p392-railsexpress/bin/ruby -S rspec ./spec/controllers/home_controller_spec.rb ./spec/models/user_spec.rb
/Users/Kassi/demo/app/decorators/controllers/blogit/comments_controller_decorator.rb:3:in `<top (required)>': uninitialized constant Blogit::CommentsController (NameError)
However, if I run the first line that rake mentions by hand (.../ruby -S ...), all tests are being run successfully.
In my project I'm using guard with spork. Running guard will also let the tests pass without any error.
The app itself runs fine, i.e. it starts without errors and I'm able to comment as I want. My decorator action code is being executed.
So what's different when running rake?
Why does it break?
Note:
Adding require "blogit" or require "blogit/comments_controller" doesn't help. It actually can't find the controller using require.
A Demo Application
Since this problem is part of a bigger project, I created a new app from scratch for testing purposes that contains only the relevant stuff: basic rails app, rspec, devise, blogit and the decorators.
It can be found here: https://github.com/kassi/decorator_demo_rspec (git://github.com/kassi/decorator_demo_rspec.git)
Another repo using testunit (which is working!) can be found here: https://github.com/kassi/decorator_demo_testunit (git://github.com/kassi/decorator_demo_testunit.git)
Instead of performing the require statements yourself, you can try activesupport-decorators that does it for you.

Setting default_url_options in test environment doesn't seem to work

I've put the following code into my config/environments/test.rb file:
config.action_mailer.default_url_options = { :host => "localhost:3000" }
however when I run my tests, all routes use http://test.host. I'm trying to work with an API that won't accept http://test.host as a valid callback URI, so I need to change this to properly receive the API response. Any idea why this isn't working? (I'm using RSpec, Guard, and Spork in my testing suite).
EDIT: Possibly relevant - this is being done inside of a controller spec.
EDIT2: It seems that it changes after a request is made via get, post, etc. Running the following code within the test:
Rails.logger.debug users_url
get 'http://google.com'
Rails.logger.debug users_url
would produce the following output:
http://localhost:3000/users
...get request related response here
http://google.com/users
Nowadays you can just set them in your test.rb like so:
Rails.application.routes.default_url_options[:host]= 'localhost:3000'
Rails.application.routes.default_url_options[:host]= 'localhost:3000'
In the developemnt.rb / test.rb, can be more concise as following:
Rails.application.configure do
# ... other config ...
routes.default_url_options[:host] = 'localhost:3000'
end
From my experience, url_options will not be passed into tests without a bit of hacking.
See e.g.
How to set locale default_url_options for functional tests (Rails)
http://www.ruby-forum.com/topic/3448797
I've frequently encountered this problem when trying to set the locale in tests. I've never used action mailer, though, so there may be a simpler way to do it.
The solution I've found for setting the default locale in url_options is just to patch actiondispatch and force it to use whatever locale I want it to. You could adapt this to your case this way:
class ActionDispatch::Routing::RouteSet
def url_for_with_default_url_options(options)
url_for_without_default_url_options(options.merge(:host => "localhost:3000" ))
end
alias_method_chain :url_for, :default_url_options
end
I put that code in a file in spec/support so it is used in rspec tests and I also require it from my env.rb file so I can use it in cucumber tests as well.
Keep in mind that this will patch it everywhere, in both test code and in actual code running under tests, and it will override any other settings for the :host key that you try to pass in (since the patch merges the fix on top of the options passed into url_for). In your case I believe that shouldn't be a problem.
Monkey patching is not a very elegant solution, though, and I used this after everything else failed. You might find a simpler solution specific to action mailer.
How are you running your tests? Maybe appending RAILS_ENV=test might help.

logging info with rails

Moving over from django / python, I am having a little trouble getting the rails logger to log all the information I want. I am wondering how/if the following can be achieved:
Having in the log format(ter) include the specific file, function name and line where the logging statement itself was found. Essentially the equivalent of LOG_MSG_FORMAT = '%(asctime)s %(levelname)s %(filename)s:%(funcName)s(%(lineno)d) : %(message)s' in python logger?
Being able to log all requests, via something similar to a django request logging middleware. Particularly, being able to log the username (if logged in) of every request.
Am I missing something obvious? or does this require (lots of) custom code?
I just found this railtie gem that might help although I imagine it will take some "custom code" to append username to logs. See the Readme section on logging specific controllers and models.
logging-rails railtie
I don't know about getting the file, function, and line number, but it's pretty easy to log from application_controller:
class ApplicationController < ActionController::Base
before_filter :log_user
def log_user
if current_user
Rails.logger.info "Processing Request for #{current_user.name}"
end
end
end
Just to add a quick note in case this is useful for someone:
The lograge gem makes rails logs much similar to django's, plus allows very neat customization, adding parameters such as remote ip address, current_user etc.
It also reduces verbosity of rendered layouts, which I anyway found unnecessary for production. It also plays nicely with logging-rails railtie mentioned by #lukewendling.
Sadly, I still couldn't find anything that shows the file/function/line number like you can easily do with django, but I guess that's just too much to ask.

Rails 3 - extend ActionController

I am trying to implement logic captcha in my app. I have scaffolded simple TextCaptcha to store question and answer in DB.
Currently I have this in initializers/text_captcha.rb
require 'text_captcha'
ActionController::Base.send(:include, TextCaptcha)
This in "lib/text_captcha.rb":
module TextCaptcha
def self.included(base)
base.send(:include, InstanceMethods)
end
module InstanceMethods
def require_text_captcha
#captcha = "hello!"
end
end
end
So in comments controller I have this to have access to #captcha in view
before_filter :require_text_captcha
The bad thing is I have to restart webrick every time I make changes - so I think I'm doing this in a wrong way? I could get rid of initializer and just require "text_captcha" where I need... Or is there a way to do this in "models/text_capctha.rb" which I was trying to do in the beginning but could figure out.
Since ApplicationController in a Rails app extends from ActionController::Base, can you do:
require 'text_captcha'
class ApplicationController < ActionController::Base
include TextCaptcha
end
in app/controllers/application_controller.rb?
If TextCaptcha is getting blown away when Rails reloads your models the fix is to use to_prepare instead of an initializer to load it. See the following resources for more information:
Official Docs: http://api.rubyonrails.org/classes/ActionDispatch/Callbacks.html#method-c-to_prepare
Short Blog Post: http://www.cowboycoded.com/2011/01/28/reloading-rails-3-engine-initializers-in-development/

Devise/Warden custom single-sign-on strategy

I want my SSO custom strategy to be the only strategy that devise uses. I'm doing this by:
config.warden do |manager|
manager.default_strategies :my_sso_strategy
end
This is where I get stuck. I want to invoke the strategy, and I thought this would be done for me by:
app/controllers/devise/sessions_controller.rb
But, it doesn't look like my strategy gets invoked.
I took away the :authenticatable / :database_authenticatable from the devise declaration in my User model thinking that may be causing the problem.
After making the sign-in/out routes manually (because :authenticatable makes them), I get an AbstractController::ActionNotFound error.
At this point I'm at a loss how to continue.
My views should be setup correctly to auto-submit my credentials I get from the SSO application (it worked in authlogic)
Has anyone done something similar to this?
I can't say for sure unless you share how you coded the strategy. The simple answer is that you need a valid? method defined to specify when to use the strategy. Since you only want to use one strategy then I would expect your valid method to be like this..
Warden::Strategies.add(:my_sso_strategy) do
def valid?
true
end
def authenticate!
#do authentication
end
end
I have seen others use the ":user" scope and noticed you did not have it in your excerpt. Perhaps that is causing the original error.
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable
end