Проблема при создании модели ActiveRecord: данные отсутствуют при сохранении - PullRequest
4 голосов
/ 10 сентября 2009

У меня проблемы с созданием новой строки модели в базе данных с использованием ActiveRecord в приложении Sinatra, которое я разрабатываю. Рассматриваемый объект создается без каких-либо ошибок (с помощью сохранения !, исключений не возникает), но большая часть данных, которые я указываю для сохранения, отсутствует.

class ProjectMeta < ActiveRecord::Base
    attr_accessor :completion_ratio, :num_stories, :num_completed_stories, :original_target_date, :current_target_date

    ...

    def self.create_from_project(project)
        meta = ProjectMeta.new
        meta.project_id = project.id
        meta.num_stories = project.num_stories
        meta.num_completed_stories = project.num_completed_stories
        meta.completion_ratio = ProjectMeta.calculate_ratio(project.num_completed_stories, project.num_stories)
        meta.current_target_date = project.current_target_date
        meta.save!
        meta
    end

    ...

end

Все проверки данных из объекта проекта, который я отправляю, а также нового мета-объекта, который я создаю, показывают, что данные присутствуют. Но когда я делаю meta.inspect до и после сохранения, это показывает, что все данные (кроме project_id) находятся в состоянии по умолчанию (нули). Я также проверил meta.errors.nil? и, конечно же, нет никаких ошибок после сохранения.

Что больше всего удивляет, так это то, что если я развернусь и получу новый метаэкземпляр с этим project_id и введу данные, это не спасет БД.

Это расстраивает меня, потому что я создал несколько сайтов в Rails и Sinatra с ActiveRecord. Этот вопрос меня совершенно сбивает с толку. Может кто-нибудь сказать мне, что я делаю не так?

Ответы [ 3 ]

6 голосов
/ 12 сентября 2009

Вот как это работает

  1. При первом доступе к модели столбцы из соответствующей таблицы базы данных извлекаются и сохраняются в данных модели. Эту информацию можно получить с помощью :: столбцов метода класса.

  2. Когда вы обращаетесь к атрибуту какой-либо модели, Ruby не находит соответствующий метод в классе и запускает метод #method_missing. Этот метод проверяет столбцы модели :: , чтобы проверить, существует ли соответствующий столбец. Если это так, он создает средства доступа для этого столбца, так что в следующий раз, когда вы получите доступ к атрибуту этой модели, метод средства доступа будет вызываться напрямую, без необходимости вызывать #method_missing (последнее медленнее).

Аксессоры выглядят так:

def my_attribute
  read_attribute(:my_attribute)
end

def my_attribute=(value)
  write_attribute(:my_attribute, value)
end

Для методов #read_attribute и #write_attribute есть ярлык: # [] и # [] = . Если по какой-то причине вам потребуется прямой доступ к базовым данным (например, выполнить какое-либо преобразование данных), вы можете записать их кратко:

def my_attribute
  self[:my_attribute]
end

def my_attribute=(value)
  self[:my_attribute] = value
end

Модель имеет специальный метод доступа - # атрибутов - который возвращает хеш "column_name => value".

ПРИМЕЧАНИЕ: данные для каждого столбца хранятся в специальном экземпляре Hash внутри экземпляра модели, а не в переменных экземпляра "@column_name". Когда вы определяете методы доступа с помощью #attr_accessor, вы блокируете обычный способ определения методов доступа с помощью #method_missing. Ваши данные хранятся в переменных экземпляра вместо хеша " attribute ", поэтому они не сохраняются в базе данных.

Если вы хотите добавить новый атрибут в вашу модель, вам действительно нужно добавить столбец в таблицу базы данных, которая соответствует этой модели, а затем перезагрузить все приложение.

1 голос
/ 11 сентября 2009

Существует важное различие между полями базы данных и временными объявленными свойствами attr_accessor. Если вы объявили свои столбцы, тогда объявления attr_accessor не нужны.

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

Например, чтобы посмотреть, что планируется сохранить:

class MyModel < ActiveRecord::Base
  attr_accessor :not_saved
end

model = MyModel.new(:not_saved => 'foo')

puts model.attributes.inspect

Существуют методы для получения информации о том, какие столбцы доступны в модели, например:

MyModel.columns_names
0 голосов
/ 11 сентября 2009

attr_accessors никогда не будет сохранен в БД. Это внутренние переменные в экземпляре. Если вы хотите сохранить значения, вы должны создать реальные столбцы.

Выполните миграцию, чтобы объявить столбцы, затем повторите попытку.

...