Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

undefined method include? for :author:Symbol when using create_with.find_or_create_by! #58

Open
pjsanjuan opened this issue Oct 25, 2023 · 0 comments

Comments

@pjsanjuan
Copy link

pjsanjuan commented Oct 25, 2023

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

scope.merge(create_with_value)

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")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant