Shoulda-matchers: `cast_type` use in rails_shim causes a problem with the serialize matcher - Rails 5

Created on 10 Mar 2016  路  28Comments  路  Source: thoughtbot/shoulda-matchers

I have seen this issue in Rails 5, and shoulda-matchers 3.1.1 (along with pulling shoulda-matchers directly from master).

IntakeRequest should serialize :payload class_name => JSON
     Failure/Error: should serialize(:payload).
     NoMethodError:
       undefined method `cast_type' for #<ActiveRecord::ConnectionAdapters::MySQL::Column:0x007f8dcc21d778>

This cast_type attribute has been removed from ActiveRecord::ConnectionAdapters::MySQL::Column per this commit

The cast_type attribute is called from within the rails_shim

I would be happy to help fix this, but could use some direction if anyone has suggestions on how best to address this.

Note: An issue was created by the cast_type change on the oracle adapter that may have useful information as they come to a resolution.

馃洡 Rails 5

Most helpful comment

@adammcfadden I had to make a small change with respect to shoulda master, and it works a treat. Thanks!

# spec/rails_helper.rb
module Shoulda
  module Matchers
    RailsShim.class_eval do
      def self.serialized_attributes_for(model)
        if defined?(::ActiveRecord::Type::Serialized)
          # Rails 5+
          model.columns.select do |column|
            model.type_for_attribute(column.name).is_a?(::ActiveRecord::Type::Serialized)
          end.inject({}) do |hash, column|
            hash[column.name.to_s] = model.type_for_attribute(column.name).coder
            hash
          end
        else
          model.serialized_attributes
        end
      end
    end
  end
end

All 28 comments

As another note, the serialized_attributes method has been removed from Rails 5 which will cause issues within the same method on the rails_shim

I have a possible solution that is using similar logic as a fix in rails_admin

/shoulda-matchers/lib/shoulda/matchers/rails_shim.rb:22

      def self.serialized_attributes_for(model)
        if defined?(::ActiveRecord::Type::Serialized)
          # Rails 5+
          model.columns.select do |column|
            model.type_for_attribute(column.name).is_a?(::ActiveRecord::Type::Serialized)
          end.inject({}) do |hash, column|
            hash[column.name.to_s] = model.type_for_attribute(column.name).coder.name.split("::").last.constantize
            hash
          end
        else
          model.serialized_attributes
        end
      end

Fix on forked repo: https://github.com/adammcfadden/shoulda-matchers/commit/9af2999ed0adf524abb845ee95d86afcb37af6e0

I have tested this against the rails 5 app that I originally discovered the issue with, and the above solution seems to be working. I will work on adding more holistic testing in with a pull request, but that will take some time as it looks like shoulda-matchers is not yet testing against rails 5.

If anyone has suggestions for refactoring (I would love to clean up hash[column.name.to_s] = model.type_for_attribute(column.name).coder.name.split("::").last.constantize ), or info about testing against rails 5 please let me know.

@adammcfadden model.type_for_attribute(column.name).coder.name.split("::").last.constantize seems like it could be model.type_for_attribute(column.name).coder.name.demodulize.constantize more or less the same thing under the covers but reads a little nicer.

Any update on this?

@fubarius I haven't put in any more work on this issue. I'm assuming that Rails 5 issues are waiting until rails 5 at least has a release candidate. @engineersmnky - nice, much cleaner!

@adammcfadden with your fix in place I hit another issue that's possibly in -context. I'll try to get the test suite passing against Rails 5 and start opening pull requests, though who knows when they'll get accepted thanks to the rather vague "changing of the guard" notice on the shoulda* projects.

@adammcfadden I had to make a small change with respect to shoulda master, and it works a treat. Thanks!

# spec/rails_helper.rb
module Shoulda
  module Matchers
    RailsShim.class_eval do
      def self.serialized_attributes_for(model)
        if defined?(::ActiveRecord::Type::Serialized)
          # Rails 5+
          model.columns.select do |column|
            model.type_for_attribute(column.name).is_a?(::ActiveRecord::Type::Serialized)
          end.inject({}) do |hash, column|
            hash[column.name.to_s] = model.type_for_attribute(column.name).coder
            hash
          end
        else
          model.serialized_attributes
        end
      end
    end
  end
end

Any news on this?

I'm seeing this as well

Is there any particular problem with applying the mentioned monkey_patch of @bsodmike to RailsShim?

any update on this being patched?

Hi! I confirm that @bsodmike's patch works :)

Thanks @leifg @n-rodriguez - I've just posted a PR for this patch.

When will this be fixed and released?

I merged @bsodmike's fix into the rails-5 branch in 28a43a3b6081deb65dc1a25a5cd6f9608728c467, so I'm going to close this to clean things up. We'll have a new pre-release out soon so people can use that instead of having to use a branch in their Gemfiles.

@mcmire Any progress on a pre-release? We're still using the branch.

@jeremywadsack Sigh. Somewhat. I've been (very slowly) working on improving some of the messages so I can debug some of the current issues better. But at this point it's completely backing things up. I'll take a look at what's left over and see if I can just finish up the remaining Rails 5 issues and put something out (even it's just an alpha) soon.

@mcmire For the people who are using the master branch, how can we fix this? Is there a workaround while we wait for the fix?

@javierojeda94 It should be fixed already, in master. Are you still experiencing issues?

@mcmire unfortunately, yes. I'm using rspec to test a serialization field on my model but I'm facint some errors on those tests:

My model make.rb

class Make < ApplicationRecord
  serialize :vehicle_types, Array
end

When I run the example it { is_expected.to serialize(:vehicle_types).as(Array) }

I got this error:

NoMethodError:
       undefined method `cast_type' for #<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x0000564663634340>

In my Gemfile.lock I have shoulda-matchers (3.1.2)

@javierojeda94 Hmm, you shouldn't be seeing that. You sure you're pointed to master? You may want to run bundle update to ensure that you're pointed to the latest commit. (The version number is the same for now -- I haven't updated it yet.)

Any update on this? I recently experienced this issue.

@mcmire

Any news?

@dillionverma @blackst0ne As far as I know this is fixed. Are you receiving the same exact error, or some variation? And you're pointed to master (and if so, you've run bundle update shoulda-matchers to update it)?

I can confirm this works perfectly on master.

A quick note to others, ensure you're following the master branch of this repository:

# Gemfile
gem "shoulda-matchers", git: "https://github.com/thoughtbot/shoulda-matchers"

@mcmire thanks again for the patch! It would be great to get this into an official release soon.

Even a .beta or .rc1 version would be very much appreciated. :)

Yep it would be nice to get a new version of shoulda-matchers out, last update was over a year ago.

https://rubygems.org/gems/shoulda-matchers/versions/3.1.2

For the record, it looks like 4.0.0.rc1 was released in Oct with Rails 5 support.

Was this page helpful?
0 / 5 - 0 ratings