Redmine 插件开发 - 如何避免插件之间重复 Table 名称和模型名称
Redmine Plugin Development - How to Avoid Duplicate Table Name and Model Name Between Plugins
我正在为 Redmine 创建一个插件。但似乎在迁移时,CREATE TABLE
使用模型名称作为 table 名称。如果我已经有另一个具有相同 table 名称的插件怎么办?
我可以做些什么来自动为 table 名称添加前缀而不更改模型名称吗?
我的问题是模型 Carro .
是否可以使用 rake 脚本来指示它创建 table 如: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
我遇到重复 table 名称问题的模型:
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
我想避免的错误,如果可能的话,不用硬编码 table:
的前缀
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
但它仍然抱怨 table 名称重复。因此,添加一个包装 class 的模块不会造成任何影响:
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
基本上我更改了模型,将其包装在一个模块中:
这是我的新模型。它覆盖 ActiveRecord 中的 属性 以设置 table 名称:
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
的变化。该模块在文件系统中表示为一个目录,以避免文件冲突。
当 运行 CREATE TABLE.
时,我的迁移文件正在调用模型的 table_name 属性
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
假设我更改了 table 名称,但没有将模型包装在模块中。查询数据库时,我得到了错误的行为:
$ rails c
irb> Carro.all
以上SELECT来自tablecarros的记录,来自第一个安装名为Carro
的模型的插件。
但是,我有一个避免冲突的模块:
$ rails c
irb> Transporte::Carro.all
现在它按预期工作,使用正确的模型并查询相关的 table。
我正在为 Redmine 创建一个插件。但似乎在迁移时,CREATE TABLE
使用模型名称作为 table 名称。如果我已经有另一个具有相同 table 名称的插件怎么办?
我可以做些什么来自动为 table 名称添加前缀而不更改模型名称吗?
我的问题是模型 Carro .
是否可以使用 rake 脚本来指示它创建 table 如: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
我遇到重复 table 名称问题的模型:
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
我想避免的错误,如果可能的话,不用硬编码 table:
的前缀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
但它仍然抱怨 table 名称重复。因此,添加一个包装 class 的模块不会造成任何影响:
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
基本上我更改了模型,将其包装在一个模块中:
这是我的新模型。它覆盖 ActiveRecord 中的 属性 以设置 table 名称:
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
的变化。该模块在文件系统中表示为一个目录,以避免文件冲突。
当 运行 CREATE TABLE.
时,我的迁移文件正在调用模型的 table_name 属性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
假设我更改了 table 名称,但没有将模型包装在模块中。查询数据库时,我得到了错误的行为:
$ rails c
irb> Carro.all
以上SELECT来自tablecarros的记录,来自第一个安装名为Carro
的模型的插件。
但是,我有一个避免冲突的模块:
$ rails c
irb> Transporte::Carro.all
现在它按预期工作,使用正确的模型并查询相关的 table。