Движок и приложение имеют одинаковое имя класса — невозможно добавить атрибуты в класс приложения.

Я разрабатываю движок для использования в ряде других приложений. Он предоставляет некоторые основные функции Player и Action для приложений, использующих концепции геймификации.

В движке есть модель Player с базовыми атрибутами и методами, которые я тестировал отдельно (с RSpec) и все работает само по себе. Я интегрирую движок с другим приложением, и все функции по умолчанию в порядке, но когда я пытаюсь расширить модель приложения Player дополнительными атрибутами, они попадают в базу данных, но недоступны из класс Руби. Я подозреваю, что проблема связана с тем, что классы Player имеют одинаковое имя и что класс приложения наследуется от класса Engine, но я не могу понять точную проблему и как ее исправить.
Объяснение /код следует:

Файлы движка

Класс игрока Engine:

module CoreEngine
  class Player < ActiveRecord::Base
    belongs_to :user, class_name: CoreEngine.user_class
    has_many :player_actions

    def add_action(some_action)
      self.player_actions.create(action: some_action)
    end

    def add_actions(array_of_actions)
      array_of_actions.each do |action|
        self.add_action(action)
      end
    end

    def total_score
      self.player_actions.sum(:points_earned)
    end
  end
end

Схема проигрывателя Engine:

create_table "core_engine_players", force: true do |t|
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "name"
  t.integer  "user_id"
end

lib/core_engine/engine.rb

module CoreEngine
  class Engine < ::Rails::Engine
    isolate_namespace CoreEngine

    config.generators do |g|
      g.test_framework      :rspec,        :fixture => false
      g.fixture_replacement :factory_girl, :dir => 'spec/factories'
      g.assets false
      g.helper false
    end
  end
end

lib/core_engine.rb

require "core_engine/engine"

module CoreEngine
  mattr_accessor :player_class
  mattr_accessor :action_class
  mattr_accessor :user_class

  def self.root
    File.expand_path(File.dirname(File.dirname(__FILE__)))
  end

  def self.models_dir
    "#{root}/app/models/core_engine/"
  end

  def self.controllers_dir
    "#{root}/app/controllers/core_engine/"
  end
end

Файлы приложения

config/initializers/core_engine.rb

CoreEngine.player_class = "Player"

Я правильно включил гем core_engine (здесь не показан)

Класс Player приложения (обратите внимание, что он наследуется от движка):

class Player < CoreEngine::Player
end

Схема проигрывателя приложения

  create_table "players", force: true do |t|
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "user_id"
    t.integer  "energy"
    t.integer  "credits"
  end

Обратите внимание, что energy и credits присутствуют. Я также проверил, что они находятся в реальной таблице Postgres через psql:

                                     Table "public.players"
   Column   |            Type             |                      Modifiers                       
------------+-----------------------------+------------------------------------------------------
 id         | integer                     | not null default nextval('players_id_seq'::regclass)
 created_at | timestamp without time zone | 
 updated_at | timestamp without time zone | 
 user_id    | integer                     | 
 energy     | integer                     | 
 credits    | integer                     | 
Indexes:
    "players_pkey" PRIMARY KEY, btree (id)

Я не получаю никаких ошибок миграции. Тем не менее, когда я запускаю консоль rails и вызываю Player, я получаю:

2.1.1p76 :001 > Player
 => Player(id: integer, created_at: datetime, updated_at: datetime, name: string, user_id: integer)

energy нигде не найти. Я уверен, что это связано с наследованием от модели двигателя Player, но я не понимаю, в чем проблема. Я могу определить методы в модели Player приложения, которые оно может вызывать, а также методы в модели Player движка, которые могут вызывать оба, но не атрибуты, подобные этому.

Я полагаю, что потенциально мог бы использовать явные методы для доступа к этим определенно существующим столбцам базы данных, но я бы предпочел, чтобы я мог просто использовать Rails/ActiveRecord, как обычно.

Это мой первый опыт работы с двигателями (первый пост тоже!), и до сих пор все было очень позитивно. Мы будем очень признательны за любую помощь!


person VCavallo    schedule 23.10.2014    source источник


Ответы (1)


Возможно, модель игрока указывает на таблицу двигателей. Проверьте это в консоли Rails с помощью Player.table_name. Если это core_engine_players, просто переопределите его в классе приложения Player.

class Player
  self.table_name = 'players'
end

person blelump    schedule 23.10.2014
comment
Хах, это точно! Спасибо!! - person VCavallo; 24.10.2014
comment
... опять же, если я сделаю это, у меня не будет доступа к таблицам базы данных, которые входят в движок (например, name — это атрибут CoreEngine::Player, который я теряю, если устанавливаю table_name в таблицу приложения. Возможно, это признак того, что я иду об этом неправильно с самого начала Любые идеи по этому поводу? - person VCavallo; 24.10.2014
comment
Короче говоря, вы не можете использовать две таблицы для одной модели (или на самом деле можете, но для этого требуется переключение имен таблиц, что будет раздражать). Если вы хотите украсить модель игрока дополнительными полями, рассмотрите возможность добавления ассоциации в ваше приложение. - person blelump; 24.10.2014
comment
Для получения функциональности, подобной декоратору, через движок, кажется ли это подходящим: edgeguides .rubyonrails.org/ ? - person VCavallo; 24.10.2014
comment
В этом случае модель движка расширяет модель основного приложения с некоторой логикой. Однако в вашем случае дело не в этом. С помощью движка вы хотите предоставить некоторую модель, а затем расширить ее в основном приложении. Вы действительно можете расширить его логику, как указано в предоставленной вами ссылке, однако вы не можете работать с базой данных таким образом. Подумайте об этом, что у вас есть базовая модель Player, предоставленная движком, а в основном приложении у вас есть какая-то другая модель, назовем ее BetterPlayer, которая belongs_to Player (через ассоциацию) и Player has_one BetterPlayer. - person blelump; 24.10.2014