Разработка плагинов Redmine - как избежать дублирования имен таблиц и моделей между плагинами - PullRequest
0 голосов
/ 15 октября 2019

Я создаю плагин для Redmine. Но похоже, что при миграции CREATE TABLE использует имя модели в качестве имени таблицы. Что если у меня уже есть другой плагин с тем же именем таблицы?

Могу ли я сделать что-нибудь, чтобы автоматически добавить префикс к имени таблицы без изменения названия модели?

Проблема, с которой я столкнулся, связана с моделью Carro .

Можно ли использовать сценарии rake, чтобы настроить его для создания таблицы, такой как: CREATE_TABLE pluginName_modelName?

Как я создал скелет плагина:

bundle exec ruby bin/rails generate redmine_plugin carros
      create  plugins/carros/app
      create  plugins/carros/app/controllers
      create  plugins/carros/app/helpers
      create  plugins/carros/app/models
      create  plugins/carros/app/views
      create  plugins/carros/db/migrate
      create  plugins/carros/lib/tasks
      create  plugins/carros/assets/images
      create  plugins/carros/assets/javascripts
      create  plugins/carros/assets/stylesheets
      create  plugins/carros/config/locales
      create  plugins/carros/test
      create  plugins/carros/test/fixtures
      create  plugins/carros/test/unit
      create  plugins/carros/test/functional
      create  plugins/carros/test/integration
      create  plugins/carros/README.rdoc
      create  plugins/carros/init.rb
      create  plugins/carros/config/routes.rb
      create  plugins/carros/config/locales/en.yml
      create  plugins/carros/test/test_helper.rb

Модель У меня возникли проблемы с повторяющимся именем таблицы:

bundle exec ruby bin/rails generate redmine_plugin_model carros Carro modelo:string ano:integer cor:string km:integer
      create  plugins/carros/app/models/carro.rb
      create  plugins/carros/test/unit/carro_test.rb
      create  plugins/carros/db/migrate/001_create_carros.rb

И миграция:

cat plugins/carros/db/migrate/001_create_carros.rb
class CreateCarros < ActiveRecord::Migration
  def change
    create_table :carros do |t|
      t.string :modelo
      t.integer :ano
      t.string :cor
      t.integer :km
    end
  end
end

И ошибку, которую я хотел бы избежать, если это возможно, без жесткого кодирования префикса для таблицы:

bundle exec rake redmine:plugins:migrate
Migrating carros (Carros plugin)...
== 1 CreateCarros: migrating ==================================================
-- create_table(:carros)
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Table 'carros' already exists: CREATE TABLE `carros` (`id` int(11) auto_increment PRIMARY KEY, `modelo` varchar(255), `ano` int(11), `cor` varchar(255), `km` int(11)) ENGINE=InnoDB                                                                            
/usr/local/www/redmine/plugins/carros/db/migrate/001_create_carros.rb:3:in `change'
/usr/local/www/redmine/lib/redmine/plugin.rb:481:in `migrate_plugin'
/usr/local/www/redmine/lib/redmine/plugin.rb:453:in `migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:467:in `block in migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `each'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `migrate'
/usr/local/www/redmine/lib/tasks/redmine.rake:135:in `block (3 levels) in <top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'

Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'carros' already exists: CREATE TABLE `carros` (`id` int(11) auto_increment PRIMARY KEY, `modelo` varchar(255), `ano` int(11), `cor` varchar(255), `km` int(11)) ENGINE=InnoDB                                            
/usr/local/www/redmine/plugins/carros/db/migrate/001_create_carros.rb:3:in `change'
/usr/local/www/redmine/lib/redmine/plugin.rb:481:in `migrate_plugin'
/usr/local/www/redmine/lib/redmine/plugin.rb:453:in `migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:467:in `block in migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `each'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `migrate'
/usr/local/www/redmine/lib/tasks/redmine.rake:135:in `block (3 levels) in <top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'

Caused by:
Mysql2::Error: Table 'carros' already exists
/usr/local/www/redmine/plugins/carros/db/migrate/001_create_carros.rb:3:in `change'
/usr/local/www/redmine/lib/redmine/plugin.rb:481:in `migrate_plugin'
/usr/local/www/redmine/lib/redmine/plugin.rb:453:in `migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:467:in `block in migrate'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `each'
/usr/local/www/redmine/lib/redmine/plugin.rb:466:in `migrate'
/usr/local/www/redmine/lib/tasks/redmine.rake:135:in `block (3 levels) in <top (required)>'
/usr/local/bin/bundle:23:in `load'
/usr/local/bin/bundle:23:in `<main>'
Tasks: TOP => redmine:plugins:migrate
(See full trace by running task with --trace)

То, что я пытался без успеха:

Добавление пространства имен(модуль) для модели:

Если правильно не понять, ActiveModel :: Name ActiveModel имеет функцию, которая генерирует имя модели, которое используется ActiveRecord :: create_table.

#ActiveModel::Name
    def model_name
          @_model_name ||= begin
            namespace = module_parents.detect do |n|
              n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
            end
            ActiveModel::Name.new(self, namespace)
          end
    end

Поэтому я попытался добавить модуль к названию моей модели:

module Tutorial
    class Carro < ActiveRecord::Base

    end
end

Но он по-прежнему жалуется на дублирующееся имя таблицы. Итак, добавление модуля, оборачивающего класс, не вызвало никакого эффекта:

bundle exec rake redmine:plugins:migrate NAME=carros
/usr/local/lib/ruby/gems/2.6/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/duplicable.rb:111: warning: BigDecimal.new is deprecated; use BigDecimal() method instead.
Migrating carros (Carros plugin)...
== 1 CreateCarros: migrating ==================================================
-- create_table(:carros)
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Table 'carros' already exists: CREATE TABLE `carros` (`id` int(11) auto_increment PRIMARY KEY, `modelo` varchar(255), `ano` int(11), `cor` varchar(255), `km` int(11)) ENGINE=InnoDB

1 Ответ

0 голосов
/ 17 октября 2019

В основном я изменил модель, заключив ее в модуль:

Это моя новая модель. Он переопределяет свойство из ActiveRecord, чтобы установить имя таблицы:

module Transporte
    class Carro < ActiveRecord::Base
        # https://github.com/rails/rails/blob/master/activerecord/test/models/developer.rb
        self.table_name = "trans_carros"
    end
end

Файловая система должна отражать изменение с models/carro.rb на models/transporte/carro.rb. Модуль представлен как каталог в файловой системе, чтобы избежать конфликта файлов.

Мой файл миграции теперь вызывает свойство table_name модели при запуске CREATE TABLE.

class CreateCarros < ActiveRecord::Migration
  def change
    say("Creating table " << Transporte::Carro.table_name)
    create_table Transporte::Carro.table_name do |t|
      t.string :modelo
      t.integer :ano
      t.string :cor
      t.integer :km
    end
  end
end

Предположим, я изменил таблицуимя без упаковки модели в модуле. При запросе к базе данных я получил неправильное поведение:

$ rails c
irb> Carro.all

Выше ВЫБРАТЬ записи из таблицы carros , от первого плагина, который установил модель с именем Carro.

Но с модулем для предотвращения конфликтов у меня есть:

$ rails c
irb> Transporte::Carro.all

И теперь он работает как положено, используя правильную модель и запрашивая соответствующую таблицу.

...