How can I mute Rails 3 deprecation warnings selectively? - ruby-on-rails

I am upgrading a Rails 2 to Rails 3 application (code not written by me).
The (well tested code) uses shoulda and Test::Unit, and extensively uses the macros should_create and should_change.
I understand from this discussion that the shoulda maintainers want to get rid of both methods but that people using Test::Unit don't find it necessary (not sure I am grasping the whole discussion though).
Anaway, is there a way to selectively turn of the deprecation warnings for specified macros? I already know from this posting that you can turn off the deprecation warnings in the Rake test output entirely by setting:
ActiveSupport::Deprecation.silenced = true
in your the test environment file and I also know that you can put specific pieces of code in a block to get them silenced:
ActiveSupport::Deprecation.silence do
# no warnings for any use of deprecated methods here
end
The latter is an option but would require me to go over all the tests and enclose the should_create macros in such a block. So I was wondering there was a way to eliminate warnings for specific macros entirely with one configuration setting?

Old question - but if you have new depreciations you'd like to selectively ignore:
ActiveSupport::Deprecation.behavior = lambda do |msg, stack|
unless /LIBRARY_NAME/ =~ msg
ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:stderr].call(msg,stack) # whichever handlers you want - this is the default
end
end
This is for ActiveSupport 3.

In fact I stil had lots of other deprecation warnings from code that was in plugins or gems I had installed. In order to avoid most of that, I overwrote the Deprecation::warn method in test_helper.rb. So instead of the previous code, use:
module ActiveSupport
module Deprecation
class << self
def warn(message = nil, callstack = caller)
# modif pvh the following lines make sure no deprecation warnings are sent
# for code that is
# not by my but in some gem or plugin...
return if silenced || callstack.grep(/myrailsappname/).blank?
# return if silenced
deprecation_message(callstack, message).tap do |m|
behavior.each { |b| b.call(m, callstack) }
end
end
end
end
end
BTW you need to replace myrailsappname with your app's name (the name of the folder it resides in). There is probably a more generic way to get that name, but I couldn't find it right now.

Can I recommend an alternative?
module ActiveSupport
class Deprecation
module Reporting
# Mute specific deprecation messages
def warn(message = nil, callstack = nil)
return if message.match(/Automatic updating of counter caches/)
super
end
end
end
end

I think I have found a solution: in test/test_helper.rb I reopened the module and overwrote macro definition with an identical definition but the deprecation warning commented out. There are probably much more elegant ways to do this though...
# modif pvh DEPREC
# reopen the module and silence the deprecation statement to avoid
# having my results overflown by these deprecation warnings...
module Shoulda # :nodoc:
module Macros
def should_create(class_name)
##::ActiveSupport::Deprecation.warn
should_change_record_count_of(class_name, 1, 'create')
end
end
end

Create a file called selective_deprecation_silencer.rb in your config/initializers folder with the following content:
#place in the following array the messages you want to silence
silenced = [/Using a dynamic :action segment in a route is deprecated/,
/Using a dynamic :controller segment in a route is deprecated/]
silenced_expr = Regexp.new(silenced.join('|'))
ActiveSupport::Deprecation.behavior = lambda do |msg, stack, deprecation_horizon, gem_name|
unless msg =~ silenced_expr
ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:stderr].call(msg, stack, deprecation_horizon, gem_name)
end
end

Related

Rails module names with acronym inflections

Looks like inflections don't work for module names with the nesting level more than one.
If you have the following in your config/initializers/inflections.rb:
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym 'VCloud'
end
Then when you create a directory under app/, say app/services/vcloud/ you will get two modules:
Vcloud #=> Vcloud
VCloud #=> VCloud
But if you create a directory with a higher nesting level, say app/services/vmware/vcloud/ you will get only one module:
Vmware::Vcloud #=> Vmware::Vcloud
Vmware::VCloud #=> NameError: uninitialized constant Vmware::VCloud
Is this a bug?
I would go with this is a bug. You can go around it with (within initializers):
module ActiveSupport::Inflector
def underscore_with_acronym_fix(string)
words = string.split('::')
return words.map(&method(:underscore)).join('/') unless words.one?
underscore_without_acronym_fix(string)
end
alias_method_chain :underscore, :acronym_fix
end
I'll make a pull request to fix this, however will need slightly more time to confirm it will not break anything. There are quite a lot of cases here.
I wonder if i could replicate this "issue".
Tried this running rails console.
> ActiveSupport::Inflector.camelize 'vcloud'
=> "Vcloud"
> ActiveSupport::Inflector.camelize 'v_cloud'
=> "VCloud"
There are test cases for all sorts of combinations below.
http://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html#method-i-acronym
https://github.com/rails/rails/blob/master/activesupport/test/inflector_test_cases.rb

Rails Footnotes partials count is always zero

I'm using the rails-footnotes gem in my Rails 3.2 applications, but I can't seem to get the footnotes to register the existence of any partials: it always shows a zero partial count.
To be able to know how many and what partials are being displayed on a view easily like this is, I think, immensely useful, so I would really like to get this working (the rest works great), but I'm not sure what the problem is and am hoping someone else has had the same problem and was able to resolve it. Is there a setting I've potentially missed?
I don't think it's relevant, but I'm using OSX 10.6.8 and had some issues getting the gem to work with Sublime Text 2 properly, but they did get resolved (details in this StackOverflow answer).
Update:
It seems that the issue only exists for haml templates, as I am getting expected output for erb templates. It would seem that only erb templates are counted/recognized...?
Update 2:
#DonHopkins' answer below got all my Haml templates to register with Rails Footnotes. I put it in my config file as follows:
config/initializers/rails_footnotes.rb
if defined?(Footnotes) && Rails.env.development?
Footnotes.run! # first of all
Footnotes::Notes::LogNote::LoggingExtensions.module_eval do
def add(*args, &block)
super
logged_message = args[2] + "\n"
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
# ... other init code
Footnotes::Filter.prefix = 'subl://open?url=file://%s&line=%d&column=%d'
end
I had a similar problem, although I am using erb templates, not haml. I fixed it with a monkey patch to rails-footnotes.
Looking at the rails-footnotes code (version 3.7.9), it looked to me like the problem is in this method:
module Footnotes
module Notes
class LogNote < AbstractNote
...
module LoggingExtensions
def add(*args, &block)
logged_message = super
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
...
end
end
end
The add method is assuming that super returns the message that is being logged, but in my testing super was returning a boolean value. To solve the problem, I created a file called footnotes_patch.rb with the following:
Footnotes::Notes::LogNote::LoggingExtensions.module_eval do
def add(*args, &block)
super
logged_message = args[2] + "\n"
Footnotes::Notes::LogNote.log(logged_message)
logged_message
end
end
If you want to try the solution, put that file in config/initializers, then restart your application.

event trigger system design in rails

i'm on the way of redesigning my activity feed, i already implemented the logic with redis and rails (wich works great by the way) but i'm still unsure how to create/trigger the events.
In my first approach i used observer, which had the downside of not having current_user available. and, using observer is a bad idea anyways :)
My preferred method would be to create/trigger the events in the controller, which should look sth like:
class UserController < LocationController
def invite
...
if user.save
trigger! UserInvitedEvent, {creator: current_user, ...}, :create
....
end
end
end
The trigger method should
create the UserInvitedEvent with some params. (:create can be default option)
could be deactivate (e.g. deactivate for testing)
could be executed with e.g. resque
i looked in some gems (fnordmetrics, ...) but i could not find a slick implementation for that.
I'd build something like the following:
# config/initializers/event_tracking.rb
modlue EventTracking
attr_accessor :enabled
def enable
#enabled = true
end
def disable
#enabled = false
end
module_function
def Track(event, options)
if EventTracking.enabled
event.classify.constantize.new(options)
end
end
end
include EventTracking
EventTracking.enable unless Rails.env.test?
The module_function hack let's us have the Track() function globally, and exports it to the global namespace, you (key thing is that the method is copied to the global scope, so it's effectively global, read more here: http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-module_function)
Then we enable tracking for all modes except production, we call event.classify.constantize in Rails that should turn something like :user_invited_event into UserInvitedEvent, and offers the possibility of namespacing, for example Track(:'users/invited'). The semantics of this are defined by ActiveSupport's inflection module.
I think that should be a decent start to your tracking code I've been using that in a project with a lot of success until now!
With the (new) rails intrumentation and ActiveSupport::Notifications system you can completely decouple the notification and the actual feed construction.
See http://railscasts.com/episodes/249-notifications-in-rails-3?view=asciicast

Mocha: Silence satisfied expectations

Very often when I have a missed expectation in a unit test using mocha, it spits out dozens or hundreds of "satisfied expectations" that I really don't care about. There's so much of it that I have to redirect testing output to a temp file, which is really annoying.
I am using Rails 2.3 and Mocha 0.10.0.
To clarify, I have the same issue as in
Mocha Mock Carries To Another Test
, and the solution there has not worked for me. However, even if I can get that resolved, I would like to suppress "satisfied expectations".
Thanks.
You could monkey patch mocha to achieve this. There's a method on Mocha::Mockery that returns the satisfied expectations which you could patch to return an empty array:
module Mocha
class Mockery
def satisfied_expectations
[]
end
end
end
If you put this in test_helper.rb it'll get picked up.
Alternatively for a bit more flexibility you could opt to only hide them when an environment variable is set:
module Mocha
class Mockery
def satisfied_expectations_with_optional
if ENV['MOCHA_HIDE_SATISFIED']
[]
else
satisfied_expectations_without_optional
end
end
alias_method_chain :satisfied_expectations, :optional
end
end
Then run your tests like this:
> MOCHA_HIDE_SATISFIED=1 rake test

Rails3: HOWTO Override/Reopen a class within a Gem and the Rails initialization process

My question is very similar to this one: How do I add a method to a ruby gem without editing the gem source?. However, this question is almost a year old and the solution that was chosen isn't the cleanest, not to me at least.
The person who provided the answer offered 3 suggestions. The first suggestion was chosen as the answer, but I would really like to figure out how to do it the second way.
I need to override an instance method of a class that is defined by a Gem. More specifically, it is the SessionSerializer class in 1.1.2 Devise. The issue is that Devise doesn't respect non-standard primary key names. It always uses id. You can see that in warden_compat.rb on Line 30, it uses the following to find a model by it's ID:
klass.constantize.find(:first, :conditions => { :id => id })
In my case, the name of my id column is application_user_id, so it is obvious that this won't work. Devise has fixed this issue in 1.1.3, however, I cannot use 1.1.3 because the Devise LDAP Authenticatable plugin does not support 1.1.3.
So here's what I've done instead. I should mention first that I tested this fix by editing the Gem source directly, so now I simply want to move it into my project.
Created a session_serializer.rb file in lib/warden/ (i.e., lib/warden/session_serializer.rb), reopened the Warden::SessionSerializer class, and redefined the deserialize method.
Modified application.rb to include lib/ in config.autoload_paths
config.autoload_paths += ["#{config.root}/lib"]
However, this doesn't seem to do the trick. It is still using the same code that is defined in the Gem source. So I have couple questions that I hope that can be answered:
Questions
What am I doing wrong here?
Does Rails load files of the paths defined in config.autoload_paths before Gems, or is it the other way around?
Thanks for the help in advance!
lib/warden/session_serializer.rb
module Warden
class SessionSerializer
def deserialize(keys)
klass, id = keys
if klass.is_a?(Class)
raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
"you can fix it by changing one character in your cookie secret, forcing all previous " <<
"cookies to expire, or cleaning up your database sessions if you are using a db store."
end
# NOTE: Original line code. Notice that it uses an :id symbol. It doesn't respect the primary key that explicity defined in the model
# klass.constantize.find(:first, :conditions => { :id => id })
# NOTE: THIS IS THE FIX
klass.constantize.find(:first, :conditions => { :application_user_id => id })
rescue NameError => e
if e.message =~ /uninitialized constant/
Rails.logger.debug "Trying to deserialize invalid class #{klass}"
nil
else
raise
end
end
end
end
I would create a file called warden.rb in initializers directory and put the monkey patch code inside the file. I use this technique often in my projects to patch a gem.
To put the patch under the lib directory, do the following:
config.autoload_paths += ["#{config.root}/lib/warden"]
PS: I know you have tried this, but it looks like your path is not correct.
PPS To understand the Rails 2.3 load sequence refer to this code.
Have you read:
http://guides.rubyonrails.org/configuring.html
?

Resources