Closed deanpcmad closed 2 years ago
You have a stacktrace I can see?
That's the thing, it doesn't give a proper stacktrace. I've attached a screenshot:
The console truncates it, but you can always get a backtrace.
begin
mycode
rescue => exception
puts exception.backtrace
end
That should print it all out. 👍
Ah, here we go:
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/store.rb:217:in `store_accessor_for'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/store.rb:207:in `read_store_attribute'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/store.rb:140:in `block (3 levels) in store_accessor'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/pay-3.0.11/lib/pay/stripe/billable.rb:8:in `stripe_account'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/pay-3.0.11/lib/pay/stripe/billable.rb:235:in `stripe_options'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/pay-3.0.11/lib/pay/stripe/billable.rb:29:in `customer'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/core_ext/module/delegation.rb:310:in `public_send'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/activesupport-6.1.4.1/lib/active_support/core_ext/module/delegation.rb:310:in `method_missing'
(irb):8:in `rescue in irb_binding'
(irb):6:in `irb_binding'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/workspace.rb:114:in `eval'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/workspace.rb:114:in `evaluate'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/context.rb:459:in `evaluate'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:541:in `block (2 levels) in eval_input'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:704:in `signal_status'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:538:in `block in eval_input'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/ruby-lex.rb:166:in `block (2 levels) in each_top_level_statement'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `loop'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `block in each_top_level_statement'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `catch'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `each_top_level_statement'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:537:in `eval_input'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:472:in `block in run'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:471:in `catch'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:471:in `run'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/2.7.0/irb.rb:400:in `start'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/console/console_command.rb:70:in `start'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/console/console_command.rb:19:in `start'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/commands/console/console_command.rb:102:in `perform'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/command/base.rb:69:in `perform'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/command.rb:48:in `invoke'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/railties-6.1.4.1/lib/rails/commands.rb:18:in `<main>'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
/home/dean/.asdf/installs/ruby/2.7.4/lib/ruby/gems/2.7.0/gems/bootsnap-1.8.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
bin/rails:5:in `<main>'
Perfect, thanks!
It looks like your pay_customers
table is missing the data json
column. Can you check your table?
Maybe one of the migrations is wrong.
I just used the standard migration installer: bin/rails pay:install:migrations
Here's my schema:
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_09_08_125550) do
create_table "customers", charset: "utf8mb4", force: :cascade do |t|
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "pay_charges", charset: "utf8mb4", force: :cascade do |t|
t.bigint "customer_id", null: false
t.bigint "subscription_id"
t.string "processor_id", null: false
t.integer "amount", null: false
t.string "currency"
t.integer "application_fee_amount"
t.integer "amount_refunded"
t.text "metadata", size: :long, collation: "utf8mb4_bin"
t.text "data", size: :long, collation: "utf8mb4_bin"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id", "processor_id"], name: "index_pay_charges_on_customer_id_and_processor_id", unique: true
t.index ["subscription_id"], name: "index_pay_charges_on_subscription_id"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`metadata`)", name: "metadata"
t.check_constraint "json_valid(`metadata`)", name: "metadata"
end
create_table "pay_customers", charset: "utf8mb4", force: :cascade do |t|
t.string "owner_type"
t.bigint "owner_id"
t.string "processor", null: false
t.string "processor_id"
t.boolean "default"
t.text "data", size: :long, collation: "utf8mb4_bin"
t.datetime "deleted_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["owner_type", "owner_id", "deleted_at", "default"], name: "pay_customer_owner_index"
t.index ["processor", "processor_id"], name: "index_pay_customers_on_processor_and_processor_id", unique: true
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
end
create_table "pay_merchants", charset: "utf8mb4", force: :cascade do |t|
t.string "owner_type"
t.bigint "owner_id"
t.string "processor", null: false
t.string "processor_id"
t.boolean "default"
t.text "data", size: :long, collation: "utf8mb4_bin"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["owner_type", "owner_id", "processor"], name: "index_pay_merchants_on_owner_type_and_owner_id_and_processor"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
end
create_table "pay_payment_methods", charset: "utf8mb4", force: :cascade do |t|
t.bigint "customer_id", null: false
t.string "processor_id", null: false
t.boolean "default"
t.string "type"
t.text "data", size: :long, collation: "utf8mb4_bin"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id", "processor_id"], name: "index_pay_payment_methods_on_customer_id_and_processor_id", unique: true
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
end
create_table "pay_subscriptions", charset: "utf8mb4", force: :cascade do |t|
t.bigint "customer_id", null: false
t.string "name", null: false
t.string "processor_id", null: false
t.string "processor_plan", null: false
t.integer "quantity", default: 1, null: false
t.string "status", null: false
t.datetime "trial_ends_at"
t.datetime "ends_at"
t.decimal "application_fee_percent", precision: 8, scale: 2
t.text "metadata", size: :long, collation: "utf8mb4_bin"
t.text "data", size: :long, collation: "utf8mb4_bin"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id", "processor_id"], name: "index_pay_subscriptions_on_customer_id_and_processor_id", unique: true
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`data`)", name: "data"
t.check_constraint "json_valid(`metadata`)", name: "metadata"
t.check_constraint "json_valid(`metadata`)", name: "metadata"
end
create_table "pay_webhooks", charset: "utf8mb4", force: :cascade do |t|
t.string "processor"
t.string "event_type"
t.text "event", size: :long, collation: "utf8mb4_bin"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.check_constraint "json_valid(`event`)", name: "event"
end
add_foreign_key "pay_charges", "pay_customers", column: "customer_id"
add_foreign_key "pay_charges", "pay_subscriptions", column: "subscription_id"
add_foreign_key "pay_payment_methods", "pay_customers", column: "customer_id"
add_foreign_key "pay_subscriptions", "pay_customers", column: "customer_id"
end
Ah, yeah your data
column is not json.
t.text "data", size: :long, collation: "utf8mb4_bin"
You're using MySQL? It supports a json column type doesn't it? I run my tests against MySQL and it uses a json column fine.
Hm. Even when setting the column type in the migration, it still does the same thing 🤔
I guess maybe MYSQL uses this to validate that it's a JSON column.
t.check_constraint "json_valid(`data`)", name: "data"
Tests run on MySQL 8: https://github.com/pay-rails/pay/blob/master/.github/workflows/ci.yml#L97
Which version are you on?
I'm using MariaDB 10.6.4, which should support it 🤔
Do you use the mysql2 gem or something else for mariadb?
Yep, mysql2. Everything else works fine so I'd rather not move all my apps back to normal MySQL.
Is there a reason you're using the JSON field and not just a normal data field? I've used serialize
multiple times with no issues on a data field, plus it works on different database types
Having a quick Google, I've found this:
- MariaDB stores JSON as true text, not in binary format as MySQL. MariaDB's JSON functions are much faster than MySQL's so there is no need to store in binary format, which would add complexity when manipulating JSON objects.
- For the same reason, MariaDB's JSON data type is an alias for LONGTEXT. If you want to replicate JSON columns from MySQL to MariaDB, you should store JSON objects in MySQL in a TEXT or LONGTEXT column or use statement based replication. If you are using JSON columns and want to upgrade to MariaDB, you need to either convert them to TEXT or use mysqldump to copy these tables to MariaDB
I still think Pay should work with any database type, especially seeing as most people are using MariaDB these days.
I just tried setting them as text in the migration and it still errors out which makes me think it's a bug with Rails?
That's unfortunate that MariaDB has implemented them as text columns. Rails will see them as text
and not json
. The store_accessor
feature only applies to columns that Rails considers json
in the schema.
Seems like Rails could be improved to treat them as json, but I'm not sure how you'd reasonably detect that.
Ah, good find.
Well I've managed to get it working by using store
which I think uses a Hash by default and all the model tests pass
store :data, accessors: [:stripe_connect_account_id, :onboarding_complete]
Ah yeah, I didn't think of trying that for some reason. I just tried attribute :data, :json
and it didn't work.
I guess the solution might be to add store :data
if it's a text column, and then we can leave the store_accessor for the attributes and I bet that works.
Will add a test and confirm that works. Then it'll probably be good to add Maria to the CI.
I've just tried to set Pay v3 up on my Rails application (and I've also created a basic Rails app to test this error) but I'm running into issues.
When using the Fake Processor, it works fine:
I'm using Rails 6.1.4.1 with MariaDB 10.5.12. I've also tried MariaDB 10.6.4.
Any ideas?