#ruby-on-rails #ruby #activerecord
#ruby-on-rails #ruby #activerecord
Вопрос:
Я создал следующий тип ActiveRecord, и хотя has_many
ассоциации работают хорошо, has_many :through
не:
# app/types/uuid_type.rb
class UuidType < ActiveRecord::Type::Binary
def serialize(value)
super(cast_to_uuid(value)amp;.raw)
end
def deserialize(value)
cast_to_uuid(super(value)).to_s
end
def cast_value(value)
cast_to_uuid(value).to_s
end
private
def cast_to_uuid(value)
return if value.nil?
case value.size
when 16 then UUIDTools::UUID.parse_raw(value) # From `uuidtools` gem
when 36 then UUIDTools::UUID.parse(value) # From `uuidtools` gem
end
end
end
# app/models/token.rb
class Token < ActiveRecord::Base
attribute :id, UuidType.new, default: SecureRandom.uuid
has_many :token_users
has_many :users, through: :token_users
end
(Я также написал целый код, чтобы воспроизвести проблему).
where
Предложение SQL, сгенерированное для has_many
, похоже на следующее и работает отлично:
WHERE column = x'4e254953bcdb4793a485ac04131565a7'
В то время как столбец, созданный для has_many :through
, не работает:
WHERE column = '4e254953-bcdb-4793-a485-ac04131565a7'
Он не возвращает никакой ошибки, но также не возвращает никаких результатов.
Проблема в том, что второй столбец ( has_many :through
) не включает x
префикс, а также не удаляет дефисы (если я сделаю это вручную, это решит проблему).
Я смог воспроизвести проблему как с MySQL, так и с SQLite, а также с Rails 5 и 6.
Почему has_many :through
связь не выдает тот же SQL для двоичного типа? И как вы можете заставить его работать так, чтобы он работал?
Комментарии:
1. Почему вы используете пользовательский AR-тип для создания,
uuid
вместо использования столбца типа mysqluuid
?2. @MartinZinovsky В отличие от PostgreSQL, я думаю, что у MySQL нет
uuid
типа 🙂 В любом случае, я бы не смог изменить это сейчас, поскольку в этой таблице уже много записей, и ее изменение нарушило бы другие вещи. Спасибо.3. К ВАШЕМУ СВЕДЕНИЮ
Mysql 8.0 has UUID support
4. Спасибо, @MartinZinovsky! Тип столбца, используемый в примере из отправленной вами ссылки, является
binary
. Это то, что я уже использую 🙂 Но Rails еще не сериализует / десериализует его из коробки, верно?
Ответ №1:
Оказывается, это была ошибка Rails.
Я отправил проблему в официальное репозиторий, и они ее исправили:
Ответ №2:
Я не уверен, поможет ли это, но перейдите в config/initializers /type.rb и добавьте
ActiveRecord::Type.register(:token_users, UuidType)
Комментарии:
1. На основе
ActiveRecord::Type.register docs
первого аргумента должно бытьtype_name
, но здесь у вас есть имя таблицы2. Я не думаю, что это проблема, иначе
has_many
(без:through
) не сработало бы.3. Я только что протестировал, это действительно не сработало. В любом случае, спасибо.