Best Practice for Detecting Rails Version for Plugin Compatibility? - ruby-on-rails

I'm working on upgrading a plugin for Rails 3.0.5, specifically, this commit. Essentially, ActiveRecord requires a proc instead of a string for condition interpolation.
In general, I think the best way to handle something like this is with a respond_to? call, but in this case all of the methods that were changed are private. What's the best practice for checking the rails version so that the plugin can give new versions a proc, and old versions a string? I'd rather not rely on checking that private methods exist, since that is likely to break in the future.

Rails.version
# => "3.0.5"
Rails::VERSION::MAJOR
# => 3
Rails::VERSION::MINOR
# => 0
Rails::VERSION::TINY
# => 5

Related

"Status is Invalid" - Active Record - Rails 4.1 -> 5.2

I'm working on upgrading a Ruby 2.2.2 (Rails 4.1) app to Ruby 2.5.7 (Rails 5.2) and for a couple of models I'm getting some errors
From searching around, it sounds like there are some generic activerecord validation rules / messages? The messages are:
Status is invalid
User is invalid`
I am a novice at best with Ruby - so any suggestions on the best way to work through this error are appreciated!
In Rails 5, whenever a belongs_to association is defined, it is required to have the associated record present by default. That means, compared to Rails 4, each belongs_to :foo association basically adds internally a validate :foo, presence: true to the code too.
You have two choices:
Follow the new Ruby on Rails conventions and fix your tests by adding all required associated objects to the models.
Switch back to the old behavior for these kinds of associations by adding , optional: true to each belongs_to :foo line in your code.
There is actually the third option to switch off this behavior in the whole application, by adding a line like this to your application.rb
Rails.application.config.active_record.belongs_to_required_by_default = true
But that means your application will not follow Ruby on Rails conventions and defaults anymore and IMHO this ofter leads to problems with a later update.
Therefore my advice is: Fix your tests now and only make those associations optional that are really optional from the user's point of view – this might take a bit longer but causes certainly less trouble in the future.

Changes to mass_assignment_authorizer cause errors in Ruby on Rails 3.1

Protecting against mass assignment as in this railscast no longer works in Rails 3.1.
Error given is:
wrong number of arguments (1 for 0)
for
app/models/user.rb:20:in `mass_assignment_authorizer'
If you're trying to implement the override technique in Ryan's Railcasts, but using Rails 3.1.0, then re-writing the private def in the model to:
def mass_assignment_authorizer(role = :default)
super + (accessible || [])
end
I found this cleared the
wrong number of arguments (1 for 0)
error above (ie just adding (role = :default), and also correlates with the answer above
Looking in the source it appears that, at least in master, there is a default option of :default for mass_assignment_authorizer as seen here.
Which version of rails 3.1 are you using?, it may be worth trying it against head by changing your Gemfile:
gem 'rails', :git => 'git#github.com:rails/rails.git'

Integrate Mongoid and CanCan

Have somebody tried to rewrite CanCan ActiverRecordAddtions for
Mongoid http://github.com/ryanb/cancan/blob/master/lib/cancan/active_record_additions.rb
Regards,
Alexey Zakharov
I've managed to get CanCan and Mongoid (version 2) to work together pretty well on a rails 3 app. Still get some errors here and there related to conditions in the permission definition (the Ability model).
I just put the contents of this gist into a file in config/initializers:
http://gist.github.com/561639
The condition hashes are almost the same as with ActiveRecord:
# can only manage own account
can :manage, User, :_id => current_user.id
I'm still working on how to use more advanced Mongoid::Criteria conditions, but you can always use a block to do more complex conditions:
# can only manage own account
can :eat, Cake do
current_user.jobs.any?{ |job| job.title == 'Peasant'}
end
I know it's an old one, but for those who search mongoid and cancancan integration, you could try official mongoid adapter
For cacancan gem version >2.0 there's separate gem cancacan-mongoid
Bear in mind that this gem status is "in development", but still it's working pretty well and build passing

Rails 3 : Anticipating migration for 2.3 beginners

I am a beginner in Rails. I use 2.3.X.
I just saw Rails 3 is pre-released [edit: now in release candidate!]. I will most probably eventually switch to it.
What are the common coding habits in 2.3 I should not take, so that the switch is as smooth as possible ?
Edit:
I've done my homework and read the Release notes. But they are far from clear for the most crucial points, for example :
1.5 New APIs
Both the router and query interface have seen significant, breaking changes. There is a backwards compatibility layer that is in place and will be supported until the 3.1 release.
This is not comprehensive enough for a beginner like me. What will break ? What could I do already in 2.3.X to avoid having troubles later ?
Looking at my personal coding habits (I have been using Rails since 1.2.x), here's a list of API changes you can anticipate according to Rails 3 release notes.
find(:all)
Avoid the usage of:
Model.find(:all)
Model.find(:first)
Model.find(:last)
in favour of:
Model.all
Model.first
Model.last
Complex queries
Avoid the composition of complex queries in favor of named scopes.
Anticipate Arel
Rails 3 offers a much cleaner approach for dealing with ActiveRecord conditions and options. You can anticipate it creating custom named scopes.
class Model
named_scope :limit, lambda { |value| { :limit => value }}
end
# old way
records = Model.all(:limit => 3)
# new way
records = Model.limit(3).all
# you can also take advantage of lazy evaluation
records = Model.limit(3)
# then in your view
records.each { ... }
When upgrading to Rails 3, simply drop the named scope definition.
Constants
Avoid the usage of the following constants in favour of the corresponding Rails.x methods, already available in Rails 2.x.
RAILS_ROOT in favour of Rails.root,
RAILS_ENV in favour of Rails.env, and
RAILS_DEFAULT_LOGGER in favour of Rails.logger.
Unobtrusive Javascript
Avoid heavy JavaScript helpers in favour of unobtrusive JavaScript.
Gem dependencies
Keep your environment.rb as clean as possible in order to make easier the migration to Bundler. You can also anticipate the migration using Bundler today without Rails 3.
The release notes are the most important thing to keep an eye on. Other than that Jeremy McAnally has some neat blog posts about the whole Rails 3 thing (and has just released a gem to help you with the migration).
I'd say, read the rails release notes and see for yourself what seems the more surprising to you. A lot of stuff changed so reading this is definitively very important.

Ruby 1.9 doesn't support Unicode normalization yet

I'm trying to port over some of my old rails apps to Ruby 1.9 and I keep getting warnings about how "Ruby 1.9 doesn't support Unicode normalization yet." I've tracked it down to this function, but I'm getting about 20 warning messages per request:
rails-2.3.5/activesupport/lib/active_support/inflector.rb
def transliterate(string)
warn "Ruby 1.9 doesn't support Unicode normalization yet"
string.dup
end
Any ideas how I should start tracking these down and resolving it?
If you are aware of the consequences, i.e. accented characters will not be transliterated in Ruby 1.9.1 + Rails 2.3.x, place this in config/initializers to silence the warning:
# http://stackoverflow.com/questions/2135247/ruby-1-9-doesnt-support-unicode-normalization-yet
module ActiveSupport
module Inflector
# Calling String#parameterize prints a warning under Ruby 1.9,
# even if the data in the string doesn't need transliterating.
if Rails.version =~ /^2\.3/
undef_method :transliterate
def transliterate(string)
string.dup
end
end
end
end
Rails 3 does indeed solve this issue, so a more future-proof solution would be to migrate towards that.
The StringEx Gem seems to work pretty well. It has no dependency on Iconv either.
It adds some methods to the String class, like "to_ascii" which does beautiful transliteration out of the box:
require 'stringex'
"äöüÄÖÜßë".to_ascii #=> "aouAOUsse"
Also, the Babosa Gem does a great job transliterating UTF-8 strings, even with language support:
"Jürgen Müller".to_slug.transliterate.to_s #=> "Jurgen Muller"
"Jürgen Müller".to_slug.transliterate(:german).to_s #=> "Juergen Mueller"
Enjoy.
That method definition is wrapped in an if-statement for Ruby 1.9. Right above it, you will find the regular definition, which shows a bit more of what this is doing. It's a method used to convert accented characters into their regular variants. E.g.: á => a, or ë => e
But this method is only used in parameterize, which is in turn defined right above transliterate. This is all still in ActiveSupport. I can't find anything that is directly calling parameterize.
So perhaps you're using parameterize or transliterate yourself, somewhere in your Rails application?
Common usage (according to the parameterize documentation) is for creating friendly permalinks from arbitrary strings, much like SO does, for example:
http://stackoverflow.com/questions/2135247/ruby-1-9-doesnt-support-unicode-normalization-yet
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Replace the body of the method with
raise "transliterate called"
and observe a backtrace which will show you where the stuff is coming from at the first call. Your app will of course collapse as well but that will likely give you the culprit from the first try.
I appreciate that this is a dirty way to solve the problem, but having read the error message I'm aware of the issue. So I want to get rid of the warnings. I dropped this code in environment.rb:
module ActiveSupport
module Inflector
# Calling String#parameterize prints a warning under Ruby 1.9,
# even if the data in the string doesn't need transliterating.
# Maybe Rails 3 will have fixed it...?
if RAILS_GEM_VERSION =~ /^2\.3/
undef_method :transliterate
def transliterate(string)
string.dup
end
end
end
end
If you'd rather not monkey patch the Inflector module, you can also do this...
Both of the following worked for me to silence this annoying "Ruby 1.9 doesn't support Unicode normalization yet" warning:
silence_stream(STDERR) {
whatever_code_caused_transliterate_to_be_called
}
or
silence_warnings {
whatever_code_caused_transliterate_to_be_called
}
This does have the disadvantage that it requires cluttering up your calling code, but it is a technique you can use generally whenever you don't want to see warnings or other output.
activesupport provides silence_stream and silence_warnings in activesupport-2.3.11/lib/active_support/core_ext/kernel/reporting.rb
String#unicode_normalize, String#unicode_normalize!, String#unicode_normalized? will be introduced in Ruby 2.2. Sample code and implementation can be seen in test case, lib/unicode_normalize.rb and lib/unicode_normalize/normalize.rb.
// U+00E1: LATIN SMALL LETTER A WITH ACUTE
// U+U+0301: COMBINING ACUTE ACCENT
puts "\u00E1" == "a\u0301".unicode_normalize(:nfc)
puts true == "a".unicode_normalized?(:nfc)

Resources