Problems updating Paperclip from plugin to gem - ruby-on-rails

I am apparently having a huge problem switching from the plugin version of Paperclip to the gem version in my app. It's been my impression that there should be no difference whatsoever between a plugin and a gem of a specified version. However, I'm not seeing this as an easy transition at all.
Rails 2.3.11, Ruby 1.8.7
The plugin version I am using is version 2.3.3 and was upgraded on August 2, 2010. Attempting to update this to the gem of the same version basically killed all my tests, not being able to load a factory model which did not have its attachment loaded. It appeared that validate_attachment_content_type was also attempting to validate the attachment presence, and couldn't find it, so everything just started breaking. Again, with the plugin there are no problems and I haven't had any problems in all this time we've been using it. On the other hand, this problem seems to not occur past version 2.3.4. That's a whole other set of problems.
Basically, in all versions from 2.3.4 and up I get the problem below:
can't convert nil into String
/home/joshua/.rvm/gems/ruby-1.8.7-p334#paperclip_upgrade/gems/paperclip-2.3.15/lib/paperclip/storage/s3.rb:163:in `extname'
/home/joshua/.rvm/gems/ruby-1.8.7-p334#paperclip_upgrade/gems/paperclip-2.3.15/lib/paperclip/storage/s3.rb:163:in `to_file'
/home/joshua/.rvm/gems/ruby-1.8.7-p334#paperclip_upgrade/gems/paperclip-2.3.15/lib/paperclip/attachment.rb:94:in `assign'
/home/joshua/.rvm/gems/ruby-1.8.7-p334#paperclip_upgrade/gems/paperclip-2.3.15/lib/paperclip.rb:279:in `avatar='
/home/joshua/railscamp/app/app/models/organization.rb:311:in `copy_membership'
in all my tests that access my organization model.
The apparent offending code in this case is attempting to clone a membership model from one organization to another, with the * line being the offending call.
def copy_membership(membership)
m = membership.clone
u = m.user.clone
u.organization = self
m.organization = self
begin
m.avatar = membership.avatar *
rescue RuntimeError
m.avatar = nil
end
m.user = u
m.save
m
end
Does this make any sense to anyone? Why would the plugin work, but the gem of the same version just wrecks everything?
Update: I also don't appear to have any paperclip rake tasks available. Any ideas?

As it turns out, we should have been checking whether the filename is valid or not, rather than depending on a generic runtime error for detecting avatar presence.

Related

Rails method global params kind_in error when upgraded

I've recently done an rails and ruby upgrade, we don't have strong params in the app (I know it's legacy).
So the way it's done in the app we have the following
def all_params_permitted(this_params = nil)
this_params = params if this_params == nil
this_params.permit!
this_params.each do |i, v|
if v.kind_in?([Hash, ActionController::Parameters])
all_params_permitted(v)
end
end
end
Which loops through all params and just accepts everything, all_params_permitted is called throughout the app I would love to add strong params but that's a no-go for now.
The issue in the above method is kind_in? the upgrade I did for this app was rails 5.0.3 to rails 6.1+ and went from ruby 2.2.6 to ruby 3.0.1 so I'm not sure why kind_in? has stopped working. This is an old app (built-in rails 2) so not sure if this has been deprecated.
Any help here would be great.
Edit
I have tried kind_of? but no dice.
the upgrade I did for this app was rails 5.0.3 to rails 6.1+ and went from ruby 2.2.6 to ruby 3.0.1
This is asking for trouble. It is strongly advised to try upgrading one minor version at a time (e.g. rails 5.0 --> 5.1 --> 5.2 --> 6.0 --> 6.1), otherwise you're very likely to break things with little information on why it's stopped working/how to fix it.
Likewise for ruby versions... At an absolute minimum I'd postpone the final upgrade to ruby v3 until your application works fine under ruby 2.7.
I'm not sure why kind_in? has stopped working
Nor am I, because that's a custom method. You haven't show us how it's defined, and nor have you shown us the error message, so it's impossible for me to say with confidence what's gone wrong.
My guess is that it's implemented something like this:
class Object
def kind_in?(classes)
classes.any? { |c| self.kind_of?(c) }
end
end
i.e. it's a little wrapper around the built-in kind_of? method.
And with that said, I still have no idea why this would have "stopped working" due to a ruby and/or rails upgrade.
Not sure about kind_in?, also didn't find any reference to that method, also as you have not posted the error so not sure about your issue. is_a?, kind_of?, instance_of? are few methods that check the object class but they check only a single class. Looking at your code one option for your condition could be:
if [Hash, ActionController::Parameters].include?(v.class)
which will check if it belongs to one of these classes.

Why does BCrypt no longer accept hashes?

Last week I upgrade Fedora to the brand new 28 release, which came with a mongodb upgrade to 3.6. See How to repair mongodb service after an upgrade to Fedora 28? for how I managed to resolve my first problem which was that mongod would no longer start. Now I'm facing an other problem on the Rails application that use this same database.
This most probably is unrelated to the mongodb upgrade, but I thought it might worth providing that context and don't miss a solution for not providing enough of it.
So since the system upgrade any login attempt on this Rails project will fail with a BCrypt::Errors::InvalidHash in Devise::SessionsController#create
error, raised at bcrypt (3.1.11) lib/bcrypt/password.rb:60:ininitialize'`. Analyzing further in a Rails console of the project, it seems any call to this method will fail:
> BCrypt::Password.create('TestPassword')
BCrypt::Errors::InvalidHash: invalid hash
from /home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:in `initialize'
I tried to bundle uninstall/reinstall bcrypt, and even use the github repository version of the bcrypt gem instead, but it didn't change anything.
Looking at /home/psychoslave/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/password.rb:60:ininitialize'`, the problem seems that the hash is not valid.
# Initializes a BCrypt::Password instance with the data from a stored hash.
def initialize(raw_hash)
if valid_hash?(raw_hash)
self.replace(raw_hash)
#version, #cost, #salt, #checksum = split_hash(self)
else
raise Errors::InvalidHash.new("invalid hash")
end
end
And the corresponding test is as follow:
def valid_hash?(h)
h =~ /^\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$/
end
The hash itself is created through BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost)), which in the platform I use call __bc_crypt(secret.to_s, salt), which seems to be calling bcrypt-3.1.11/ext/mri/bcrypt_ext.c.
More importantly, adding a binding.pry in the valid_hash? method, it's possible to see what the hash value returned for a call to BCrypt::Password.create('TestPassword'), it's actually a rather long string whose start seems usual, but end up with what is most likely misgenerated sequence:
"$2a$10$Eb1f8DSkGh4G1u5GicyTYujBk6SwFXKYCH.nqxapmBlqJ0eFYdX32\x00\x00\x00\x00\xD1F\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00T\xBD\x02\x00\x00\x00\x00\x00\xF1V\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xE2\xB0\x02\x00\x00\x00\x
00\x00AW\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00 \x04\x00\x00\x00\x00\x00\x00\x86\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xB5\xF8\x0E\x00\x00\x00\x00\x00q\xD8\x01\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00…"
I can provide a dump of a whole hash if it might be of any interest (around 32Ko!).
Here is a circumvent solution which make rspec of bcrypt pass all tests successfully again.
This is really a uggly hack while waitting a proper solution, but does the job until then. Just change ~/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bcrypt-3.1.11/lib/bcrypt/engine.rb (path to adapt, of course), line 51 from:
- __bc_crypt(secret.to_s, salt)
+ __bc_crypt(secret.to_s, salt).gsub(/(\n|\x00).*/, '')
That is, trunk the string starting at the first "\x00" or "\n" occurrence, if any.
Credit note: this version of the hack was proposed by Andrey Sitnik, and I replaced the one I proposed here independently, before discovering it.
After that, BCrypt::Password#create will function again:
> BCrypt::Password.create('TestPassword')
=> "$2a$10$YPRnQF3ZihXHpa9kSx7Mpu.j28PlbdwaNs2umSQvAGkS.JJ.syGye"
I had this issue with a (very) old application and BCrypt 3.1.10. Upgrading to 3.1.12 resolved the issue. :)

How to duplicate object "by value" in Rails?

I need to duplicate a product in my spree application. So
def my_duplicate_product(product)
product.dup.tap do |new_product|
new_product.slug = "#{product.slug}-#{rand(1000)}"
...
This code causes the original product#slug to be changed.
What am I supposed to do to get a copy of that particular product and leave the original unchanged?
Rails version: 4.0.3
Update:
The problem is not in Ruby, nor Rails — it's all about globalize gem (v. 4.0.0).
This error was fixed in 4.0.3.
It realy broke #dup so some values were "shared" between the original model and the duplicated one.
See GitHub issue tracker for more information: https://github.com/globalize/globalize/pull/352
Maybe clone works:
def my_duplicate_product(product)
product.clone.tap do |new_product|
new_product.slug = "#{product.slug}-#{rand(1000)}"
Clone method on ruby doc
Update globalize gem to 4.0.3
See GitHub issue tracker for more information: https://github.com/globalize/globalize/pull/352

Initializer being called before gem in Ruby 2.1

I have a Rails 3.2 app running on Ruby 1.9.3, and I was asked to update it to Ruby 2.1 and, later, Rails 4.1. I'm having a problem upgrading to Ruby 2.1 though:
Our company have a gem that's used by our systems and defines some global constants. The application has to overwrite these constants in development (we know it's hacky, but it's temporary until we can get our staging server back on), so I have an Initializer file that overwrites these constants. That worked fine so far, I get some warnings on the server console (warning: already initialized constant ...) but it worked.
Now, however, Rails seems to be calling my custom initializer before the gem, does anyone know of a change in Ruby 2.0 or 2.1 that may induce this change of behaviour? Note that I'm still using Rails 3.2, I just updated a few gems to make it compatible with the new Ruby.
This is how I set the constant in the initializer and gem (both files have the same name and are basically the same). The constant that needs to be overwritten is URL_PORTAL:
module Portal
module Sso
URL_PORTAL_PRODUCTION = "(URL1)"
URL_PORTAL_DEVELOPMENT = "(URL2)" # I overwrite this in the initializer
URL_PORTAL_TEST = "(URL3)"
URL_PORTAL = case Rails.env
when "production" then URL_PORTAL_PRODUCTION
when "test" then URL_PORTAL_TEST
else URL_PORTAL_DEVELOPMENT
end
end
end
You can add require 'portal/seo' (or other appropriate filename) in the begining of the file.

Delayed_job won't make any changes to database

I am having many problems running DJ. Primarily, I cannot get delayed_job running any methods that change the database. I am testing locally with a sqlite3 database, DJ 3.0.0, and I even added the delayed_job_active_record gem.
I have, for example, tried to run the following method in the background:
#user = User.find(1)
#user.delay.recorder_method
Where this method is:
def recorder_method
self.relevant_field +=1
update
end
This creates a delayed job, and the handler has the appropriate info for the user and the appropriate method name. The script runs the job, thinks it has succeeded and thus deletes the record from the delayed_job table. BUT the user is unchanged (the database is unchanged).
What on earth is going wrong? Note that, when I run the same code ("#user.delay.recorder_method") from rails console, it works.. and the difference is the handler created by the rails console call is:
--- !ruby/object:Delayed::PerformableMethod
object: !ruby/ActiveRecord:User
attributes:
... (attribute info and rest of file)
Whereas the one created in by the call in a controller action is:
--- !ruby/struct:Delayed::PerformableMethod
object: !ruby/ActiveRecord:User
attributes:
Not the difference in line 1 of both things (ruby/object vs ruby/struct.. the former works and the latter doesn't). Maybe this is something that might signal what is going wrong. Any ideas, anybody?
Your Rails app is running an old version of the DJ gem and your console is running a new one. About six months ago, Delayed::PerformableMethod was refactored from a Struct into a regular class: https://github.com/collectiveidea/delayed_job/commit/7b8a79a72c0ee5d8bac4bc0b183d1cce9cedff85 (So your Rails app is running a gem at least six months old and your console is running one newer than that).
This is an easy fix. First update the appropriate line in your Rails Gemfile. You'll see a line like this:
gem 'delayed_job_active_record'
If it has a version specification, make sure it's updated to the newest. Then from the command line (in the Rails root), run:
bundle update delayed_job_active_record
For anyone interested, removing the following lines from boot.rb solved this issue for me:
require 'yaml'
YAML::ENGINE.yamler = 'syck'

Resources