Engine и App имат едно и също име на клас - не могат да добавят атрибути към класа на App

Разработвам двигател, който да се използва в редица други приложения. Той предоставя някои основни Player и Action функционалности за приложения, използващи концепции за геймификация.

Двигателят има Player модел с основни атрибути и методи, които съм тествал отделно (с RSpec) и всичко работи самостоятелно. Интегрирам двигателя с друго приложение и цялата функционалност по подразбиране е наред, но когато се опитам да разширя модела Player на приложението с допълнителни атрибути, те го правят в db, но не са достъпни от клас Ruby. Подозрението ми е, че проблемът е свързан с факта, че класовете Player имат едно и също име и че класът на приложението наследява от класа на двигателя, но не мога да разбера точния проблем и как да го поправя.
Обяснение /кодът следва:

Файлове на двигателя

Клас играч на двигателя:

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

Схема на плейъра на двигателя:

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)


Възможно е моделът на Player да сочи към таблицата на двигателя. Проверете го в конзолата на Rails от Player.table_name. Ако е core_engine_players, просто го заменете в класа на плейъра на приложението

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