the Devise timeout message doesn't correspond to the users set I18n.locale - devise

In my rails app I set the I18n.locale based the on the subdomain using a before_filter in the application controller as well as in any controller that inherits from a devise controller(Confirmations, Password and Sessions controllers).
def set_locale
unless Rails.env.test?
sd = request.subdomain.to_s[-2..-1]
I18n.locale = I18n.available_locales.map(&:to_s).include?(sd) ? sd : I18n.default_locale
end
end
I've also included the corresponding devise language files and all of my devise messages are showing up in the correct language except when there is a sessions timeout. In these instances the message shows up randomly, sometimes in the correct language and sometimes not. I believe it isn't looking at the current subdomain to set the language but is using whatever the locale was set as the last time a request to the server was made.
I thought this might have to do with the Devise FailureApp so in lib/custom_failure.rb which inherits from the Devise FailureApp I set the locale there as well but that still didn't work.
I am currently using a hack where I've set the devise.failure.timeout message to an empty string and if I detect an empty string in a flash notice then I set flash[:alert] = t('devise.failure.timedout). Timedout is a custom devise message thats set to what devise.failure.timeout is supposed to be before I hacked it.
Is this an issue with Devise or is there a Devise controller that I'm missing where I need to set the locale, any help will be greatly appreciated.

Related

Rails 3.2 Serialize & Deserialize Mail

I'm trying to save email to a database, to send it later via a rake task. It was pretty easy in rails 2.3.8 (TMail), but I'm having trouble with rails 3.2.
Once I get the Mail object (mail), I call mail.encoded to serialize the email. I save this to the database.
My rake task loads the encoded message, but I can't find a way to recreate the mail object and call deliver (deserialize).
Mail.new(mail.encoded) seems like it should work, but the delivery fails because Mail.new doesn't get the default ActionMailer SMTP settings.
Anyone else doing something like this?
Thanks!
Alright, got this working.
To serialize the email I do the following.
email = mail(:to => 'to#me.com', ....)
string = mail.encoded
# later one
mail.new(email.string)
Mail.deliver(mail)
This appears to skip any HTML validation.
I can't set the Mail send settings (SMTP, etc), but I think it defaults to :sendmail, and that's working on the web server.

Rails, A method to be called only in production

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

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.

Rails3 Devise custom routing for confirmable module

I am trying to route a user to a custom welcome page after they confirm their account via devise's confirmable. The custom page is located at /districts/setup/, reachable by districts_setup_path.
To do this I added the custom route,
devise_for :users, :controllers => { :registrations => 'registrations', :confirmations => 'confirmations' }
and created my own controller. Then I had to overload the confirmations_controller.rb and now have:
(app/controllers/confirmations_controller.rb)
class ConfirmationsController | Devise::ConfirmationsController
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message(:notice, :confirmed) if is_navigational_format?
sign_in(resource_name, resource)
redirect_to districts_setup_path
else
render_with_scope :new
# not:
# respond_with_navigational(resource.errors, :status => :unprocessable_entity){
end
end
end
This works well, but I am nervous that I am not doing this in the mostideal and robust way. In particular, I just deleted the respond_with_navigational( ... ) lines which I really don't understand.
I am hoping to write this all up in a how-to for the Devise wiki, and am just looking for feedback being fairly new to rails and even newer to Devise/engines/warden.
Taking a look on Devise's ConfirmationsController you can spot the protected method after_confirmation_path_for(resource_name, resource). Overriding it (rather than the whole action) will produce the same results with less effort.
Generally speaking, there is no problem with overriding Devise's controller since they represent the default behavior which doesn't always suit the application needs. That being said you must take a few things before overriding Devise's code:
Devise is not just another component of the system - it handles user authentication, which is a very sensitive issue. Make sure you don't break anything important before you commit it. You can do so by forking the Devise project from github, making your changes, and running the tests.
As you make changes to devise and override its code, it will become harder to upgrade to newer version, which might be incompatible with your changes.
If you do decide to make a change, look for the smallest change possible to achieve your goal. In most of the cases Devise's team has already foreseen the need for customization in certain places and left methods (like the one above) which are dedicated just for it. Again, going over the file's code on Devise's GitHub would give you a good idea as for what is the best way to customize its behavior to your needs.

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