Tag: routes

Upgrading to Rails 4.1 from Rails 4.0 – Ruby on Rails

Upgrading to Ruby on Rails 4.1 was much easier than moving from 3.2 to 4.0. Maybe because I try to keep all the apps up-2-date, maybe because Rails guys didn't change much stuff ;) (or maybe both). Either way, lets get through it.

Paperclip - String based terminators are deprecated, please use a lambda

DEPRECATION WARNING: String based terminators are deprecated, please use a lambda. 
(called from has_attached_file at app/config/initializers/paperclip_extensions.rb:22)

Well this one is really simple - just update Paperclip gem:

bundle update paperclip

More about this issue here.

The ability to pass in strings as a class name to set_fixture_class
will be removed

Next deprecation warning:

DEPRECATION WARNING: The ability to pass in strings as a class name to `set_fixture_class`
 will be removed in Rails 4.2. Use the class itself instead. 
(called from block in initialize at gems/activerecord-4.1.0/lib/active_record/fixtures.rb:465)

It you use Rspec you probably won't see this issue at all (or if you don't use fixtures). One of my apps unfortunately still does. Solution to this is really simple. Instead of:

set_fixture_class scanlation_categories:  'Scanlation::Category'
set_fixture_class scanlation_chapters:    'Scanlation::Chapter'
set_fixture_class scanlation_pages:       'Scanlation::Page'

use the class name itself (not its string version):

set_fixture_class scanlation_categories:  Scanlation::Category
set_fixture_class scanlation_chapters:    Scanlation::Chapter
set_fixture_class scanlation_pages:       Scanlation::Page

NameError: undefined method `_run_suite' for class `Test::Unit::Runner'

MiniTest::Unit::TestCase is now Minitest::Test. From /unit/testcase.rb:8:in `<module:Unit>'
rake aborted!
NameError: undefined method `_run_suite' for class `Test::Unit::Runner'
gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
gems/activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
app/test/test_helper.rb:23:in `<top (required)>'

Just get rid of this line from your test/test_helper.rb file:

require 'test/unit'

cannot load such file -- polyamorous (LoadError)

in `require': cannot load such file -- polyamorous (LoadError)
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from /ransack/lib/ransack/adapters/active_record/context.rb:3:in `<top (required)>'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from gems/ransack-d51c78f9071f/lib/ransack/adapters/active_record.rb:4:in `<top (required)>'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from /activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from gems/ransack-d51c78f9071f/lib/ransack.rb:24:in `<top (required)>'
from /bundler-1.5.2/lib/bundler/runtime.rb:76:in `require'
from /bundler-1.5.2/lib/bundler/runtime.rb:76:in `block (2 levels) in require'
from /bundler-1.5.2/lib/bundler/runtime.rb:72:in `each'
from /bundler-1.5.2/lib/bundler/runtime.rb:72:in `block in require'
from /bundler-1.5.2/lib/bundler/runtime.rb:61:in `each'
from /bundler-1.5.2/lib/bundler/runtime.rb:61:in `require'
from /bundler-1.5.2/lib/bundler.rb:131:in `require'
from app/config/application.rb:6:in `<top (required)>'
from app/config/environment.rb:1:in `require'
from app/config/environment.rb:1:in `<top (required)>'
from app/spec/spec_helper.rb:21:in `require'
from app/spec/spec_helper.rb:21:in `<top (required)>'
from app/spec/controllers/portal/announcements_controller_spec.rb:1:in `require'
from app/spec/controllers/portal/announcements_controller_spec.rb:1:in `<top (required)>'
from /rspec-core-3.0.0.beta2/lib/rspec/core/configuration.rb:932:in `load'
from /rspec-core-3.0.0.beta2/lib/rspec/core/configuration.rb:932:in `block in load_spec_files'
from /rspec-core-3.0.0.beta2/lib/rspec/core/configuration.rb:932:in `each'
from /rspec-core-3.0.0.beta2/lib/rspec/core/configuration.rb:932:in `load_spec_files'
from /rspec-core-3.0.0.beta2/lib/rspec/core/command_line.rb:21:in `run'
from /rspec-core-3.0.0.beta2/lib/rspec/core/runner.rb:100:in `run'
from /rspec-core-3.0.0.beta2/lib/rspec/core/runner.rb:31:in `invoke'
from /rspec-core-3.0.0.beta2/exe/rspec:4:in `<top (required)>'
from /home/mencio/.rvm/gems/ruby-2.1.0@senpuu/bin/rspec:23:in `load'
from /home/mencio/.rvm/gems/ruby-2.1.0@senpuu/bin/rspec:23:in `<main>'
from /home/mencio/.rvm/gems/ruby-2.1.0@senpuu/bin/ruby_executable_hooks:15:in `eval'
from /home/mencio/.rvm/gems/ruby-2.1.0@senpuu/bin/ruby_executable_hooks:15:in `<main>'

To remove this issue, upgrade your Ransack, MetaSearch and Squeel gems to newest versions and/or add this to your Gemfile:

gem 'polyamorous', github: 'activerecord-hackery/polyamorous'

 undefined method `reverse!' for #<ActiveRecord::Relation []>
Shared Example Group: "has valid single" 
called from ./spec/controllers/episodes_controller_spec.rb:13
./lib/system/active_record/nearable.rb:54:in `near'
./app/views/portal/episodes/show.html.haml:43:in `block in _app_views_episodes_show_html_haml'
./app/views/portal/episodes/show.html.haml:1:in `_app_views_episodes_show_html_haml'
./app/controllers/application_controller.rb:68:in `respond_with'
./app/controllers/portal/base_controller.rb:64:in `respond_with'
./app/controllers/portal/episodes_controller.rb:13:in `show'
./spec/support/macros/controllers/actions.rb:80:in `block (4 levels) in <module:Actions>'

With ActiveRecord 4.1, you can't call reverse! directly on ActiveRecord::Relation. Example:

# This will throw an error
@articles = Article.limit(10).order('created_at DESC').reverse!

Instead you have to cast ActiveRecord::Relation to an array:

@articles = Article.limit(10).order('created_at DESC').to_a.reverse!

Keep in mind, that casting with to_a will deprive you from all benefits of lazy loading with Rails relations so use it carefully. But on the other hand, reverse! on ActiveRecord::Relation did the same, so if you used it and it was ok, than feel free ;)

Undefined method `graft' for class ActiveRecord::Associations::JoinDependency

gems/activesupport-4.1.0/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method': 
undefined method `graft' for class `ActiveRecord::Associations::JoinDependency' (NameError)
activesupport-4.1.0/lib/active_support/core_ext/module/aliasing.rb:32:in `alias_method_chain'
from gems/polyamorous-0.6.4/lib/polyamorous/join_dependency.rb:7:in `block in included'
from gems/polyamorous-0.6.4/lib/polyamorous/join_dependency.rb:5:in `class_eval'
from gems/polyamorous-0.6.4/lib/polyamorous/join_dependency.rb:5:in `included'
from gems/polyamorous-0.6.4/lib/polyamorous.rb:20:in `include'
from gems/polyamorous-0.6.4/lib/polyamorous.rb:20:in `<top (required)>'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from gems/ransack/lib/ransack/adapters/active_record/context.rb:3:in `<top (required)>'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `block in require'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:232:in `load_dependency'
from gems/activesupport-4.1.0/lib/active_support/dependencies.rb:247:in `require'

Just install the newest version of ransack gem.

gem 'ransack', github: 'ernie/ransack'

Scoped order and limit are ignored, it's forced to be batch order and batch size

This is quite logical - you can't have some of orders when batching (for example a RAND()). That's why ActiveRecord is ignoring it. Just keep that in mind ;)


Token.2.1.0 :001 > Token.order('RAND()').find_each{}
W, [2014-05-09T11:26:46.601539 #11569]  WARN -- : 
Scoped order and limit are ignored, it's forced to be batch order and batch size
D, [2014-05-09T11:26:46.698603 #11569] DEBUG -- :   
Token Load (3.7ms)  SELECT  "accounts".* FROM "accounts"   ORDER BY "accounts"."id" ASC LIMIT 1000

Other issues

Well to be honest I didn't have any more issues. I've decided to remove Squeel gem from all of my projects, since it is not currently maintained. Thanks to that I've finally got rid of this irritating deprecation warning:

DEPRECATION WARNING: Core extensions are deprecated and will be removed in Squeel 2.0.
 (called from /app/config/initializers/squeel.rb:2:in `block in <top (required)>')


Rails 4.1 is not a big step, although it is a required one if you want to upgrade to 4.2 in the future. If you have decent test coverage level, you should not have big issues with this upgrade.

Upgrading to Rails 4.0 from Rails 3.2 – Test case – Part II (assets, models)

Here's the second part of tutorial on how to migrate from Rails 3.2 to Rails 4.

Assets - why aren't they working in a proper way?

No non-fingerprinted asset files versions for you. I've noticed this issue in a really painful way: on the production. It isn't documented anywhere, so I assume, that this is a bug (nasty one btw). When you perform:

rake assets:precompile

It generates whole bunch of files, however you might notice, that there's no non-fingerprinted once there. All of them include fingerprints. I've even tried to disable fingerprinting at all with:

config.assets.digest = false

but Rails keeps ignoring that.

My first reaction after I've noticed that, was like that:

Assets stap

I do like digest idea, but there are some libraries (like Ckeditor) that won't work without "clean" file versions. So until it is fixed, I'll be using a simple rake task that I've created:

  require 'ostruct'

  desc 'Creates a non-digest version of all the digest assets'
  task fix_assets: :environment do
    require 'fileutils'
    regexp = /(-{1}[a-z0-9]{32}*\.{1}){1}/

    assets = File.join(Rails.root, 'public', Susanoo::Application.config.assets.prefix, "**/*")
    Dir.glob(assets).each do |file|
      next if File.directory?(file)
      next unless file =~ regexp

      source = file.split('/')
      source[source.length-1] = source.last.gsub(regexp, '.')

      non_digest = File.join(source)
      File.delete(non_digest) if File.file?(non_digest)

      FileUtils.cp(file, non_digest)

This will go through all the assets and will copy fingerprinted versions to non-fingerprinetd once. It should be executed after assets precompilation:

rake assets:precompile
rake fix_assets


There's whole bunch things that were changed in ActiveRecord:

All method

All method will now return a new relation instead of Array:

# previously:
News.all.class #=> Array

# in Rails 4
News.all.class #=> ActiveRecord::Relation::ActiveRecord_Relation_News

Thanks to that, we can do chainings on an all method.

Load method

Load causes the records to be loaded from the database if they have not been loaded already. You can use this if for some reason you need to explicitly load some records before actually using them. The return value is the relation itself, not the records. You can treat this a bit as a replacement for all method.

None scopes

None scopes are one smart way to handle privileges management for AR resources (but not only for that!). Sometimes we want to create a method, that returns limited amount of objects based on incoming data. In previous Rails versions we would normally return an empty array if we wouldn’t have any privileges. However that might be troublesome when we're chaining scopes:

class Fancy < ActiveRecord::Base
  def self.resources_for(user)
    user.has_role?(:admin) ? all : []

This obviously won't work with chaining (will raise an error):

# Will raise undefined method `active' for []:Array fir bith cases

In Rails4 we can use none scope that will allow us to chain as many scopes as we want. The none scope is implemented with ActiveRecord::NullRelation. No queries will be performed on the database:

class Fancy < ActiveRecord::Base
  def self.resources_for(user)
    user.has_role?(:admin) ? all : none

Now the chaining will work perfectly.

Not query

Let's allow Rails to talk:

News.where.not('title LIKE ?', rejected_title)
News.where.not(title: rejected_title)
# It was in Mongoid for a while and finally we have it in AR also

update in favour of update_attributes

You can use update now instead of update_attributes. No need to worry due: update_attributes will stay with as for a while also.

@news = News.last

# Rails 3
@news.update_attributes(title: 'Rails 3 is quite old')
# Rails 4
@news.update(title: 'Rails 4 is new and shiny!')

Of course they both do the same.

protected attributes are out

Finally! I've never like this idea. It should not be a models responsibility to manage privileges. I will talk about that more in the next part but for know you need to know that Rails 4 moved the parameter sanitization from the model to the controller layer.

ordering for scopes works in a different way


For more details please see this blog post and this github commit!

I won't even try to count how many times I had to create a scope that looked just like a different one but with a different order. Luckily it ends now! Rails 4 ordering changes the order order :-) Until now any new order has been appended as a last one. This caused troubles sometimes:

class Fancy < ActiveRecord::Base
# Let's assume that this is a scope that is used in many, many places
scope :active, ->{ where(active: true).order('created_at ASC') }

I would love to list all the active Fancy objects, but in a different order. I don't want to change that scope, since it is widely used. So what can we do? Probably we would need to create a new similar scope. But not in Rails 4! In Rails 4 orders aren't appended but instead they are prepended, so we can create scopes with default sort order but change it on demand:

class Fancy < ActiveRecord::Base
# Let's assume that this is a scope that is used in many, many places
scope :active, ->{ where(active: true).order('created_at ASC') }

# created_at ascending sort
# SELECT `fancies`.* FROM `fancies` WHERE `fancies`.`active` = 1 \
# ORDER BY `fancies`.`created_at` ASC

# created_at descending sort
# SELECT `fancies`.* FROM `fancies` WHERE `fancies`.`active` = 1 \
# ORDER BY `fancies`.`created_at` DESC, `fancies`.`created_at` ASC
Fancy.active.order('created_at DESC')

First this might cause you a bit of troubles, especially if you're using meta_search or Ransack. You'll need to rewrite most of your search invocations. But in a longer perspective, this change is really good. If you want to pass multiply sorting orders, instead of doing something weird like that:

# This will generate sorting first by title and then by created at
Fancy.all.order('created_at DESC').order('title ASC')

You may want to use this syntax:

# Here order will be from left to right
Fancy.all.order('title ASC', 'created_at DESC')

regexp validation for validates_format_of

After trying to run your Rails app, you may see such an ArgumentError

ArgumentError: The provided regular expression is using multiline anchors (^ or $),
which may present a security risk. Did you mean to use \A and \z,
or forgot to add the :multiline => true option?

If you don't expect multiline incoming data, you need to replace all the "^" with "\A" and all the "$" with "\z". If you expect multiline strings, just specify the multiline: true option. After that, you're ready to go.

auto_explain_threshold_in_seconds is gone

Just remove it from your config file and:


MySQL strict mode

Not sure if it came with Rails 4 - but I like that! If you encounter such an error:

ActiveRecord::StatementInvalid: Mysql2::Error: Field 'seo_url' doesn't have a default value:
INSERT INTO `texts` (`name`, `seo_url`) VALUES ('name')

You need to change your tables and define default values for columns that cannot be null:

change_column :logs, :action, :string, :limit => 255, :null => false, :default => ''

find_or_initialize_by in favour of find_or_initialize_by_attr1_and_attr2

DEPRECATION WARNING: This dynamic method is deprecated.
Please use e.g. Post.find_or_initialize_by(name: 'foo') instead.

It means that instead of:

Post.find_or_initialize_by_name_and_title(name, title)

You should do this:

Post.find_or_initialize_by(name: name, title: title)

Something is wrong when we inherit not directly from ActiveRecord

Well this is not a feature - more like a bug to me. When you inherit from an abstract class that inherits from AR:

class Abs < ActiveRecord::Base
  self.abstract_class = true

class Ebs < Abs
  self.table_name = :ebses

and you try to use such an object, you might get an error:

ActionView::Template::Error: Mysql2::Error: Incorrect table name '': SHOW FULL FIELDS FROM ``

Didn't figure that out yet. Unfortunately I had to do a workaround and I've extracted common functionalities into a module that is included in all the classes that were inheriting from my abstract class.

Update: You can find the solution here: http://stackoverflow.com/questions/27914918/ruby-on-rails-rake-throwing-incorrect-table-name-error-after-updating-rails-pr

In general, just don't declare relations in an abstract class.

Copyright © 2024 Closer to Code

Theme by Anders NorenUp ↑