undefined method `include?` for :author:Symbol when using `create_with.find_or_create_by!`
Opened this issue · 0 comments
Environment
rails 5.2.8.1
active_record-acts_as 4.0.3
Note: Higher versions of rails don't seem to have this issue (e.g. rails 6.1.7)
# schema.rb
ActiveRecord::Schema.define(version: 2023_10_25_160214) do
create_table "books", force: :cascade do |t|
t.string "author"
t.string "external_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.integer "price"
t.string "actable_type"
t.integer "actable_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["actable_type", "actable_id"], name: "index_products_on_actable_type_and_actable_id"
end
end
Description
I'm running into an error where when chaining the create_with
and find_or_create_by!
methods.
>> b = Book.create_with(author: "martin").find_or_create_by!(external_id: "1231236")
Book Load (0.1ms) SELECT "books".* FROM "books" WHERE "books"."external_id" = ? LIMIT ? [["external_id", "1231236"], ["LIMIT", 1]]
Traceback (most recent call last):
2: from (irb):5
1: from (irb):6:in `rescue in irb_binding'
NoMethodError (undefined method `include?' for :author:Symbol)
I think I've traced it down to this call in the scope_for_create
method
My reasoning for thinking this is that Rails 5.2.8.1 seems to stringifies their keys in the scope_for_create
method https://github.com/rails/rails/blob/8030cff808657faa44828de001cd3b80364597de/activerecord/lib/active_record/relation.rb#L468-L468
So I overrode the scope_for_create
method from the acts_as
gem and it seems to work fine
module ActiveRecord
module ActsAs
module ScopeForCreate
def scope_for_create(attributes = nil)
unless acting_as?
if Gem::Dependency.new("", ">= 5.2.1", "< 5.2.2").match?("", ActiveRecord.version) # rubocop:disable Style/GuardClause
return super(attributes)
else
return super()
end
end
scope = respond_to?(:values_for_create) ? values_for_create(attributes) : where_values_hash
scope.merge!(where_values_hash(acting_as_model.table_name))
scope.merge!(attributes) if attributes
scope.merge(create_with_value.stringify_keys) # stringify keys here
end
end
end
end
I'll be upgrading to rails 6 eventually (where this issue doesn't exist), but in the meantime, is overriding this one line appropriate? Or could it cause potential issues with other queries?
Update: As an alternative solution I found that you can use a hash in the create_with
like Book.create_with("author" => "martin").find_or_create_by!(external_id: "1231236")