Rails STI используя ОДНУ форму - PullRequest
6 голосов
/ 01 февраля 2010

У меня есть форма, которая позволяет мне добавлять файлы разных форматов в поток. Итак, поток состоит из множества файлов, эти файлы являются файлами XML, но в основном имеют разные схемы. У меня есть одна форма, которая позволяет пользователю добавлять любой файл, который он хочет, я использую STI (который отлично работает, когда данные уже находятся в таблице), моя проблема заключается в добавлении данных в таблицу.

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

Должен ли я (или могу ли я) добавить раскрывающийся список с возможными типами и вызвать это поле как «тип», чтобы при отправке формы рельсы создавали тип записи объекта, поскольку предоставляется атрибут типа?

Какая лучшая практика для этого .. Я бегу рельсами 2.3.4.

Ответы [ 2 ]

3 голосов
/ 03 февраля 2010

Я нашел решение на http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/#comment-1826

class GenericClass < ActiveRecord::Base
  class << self
    def new_with_cast(*a, &b)
      if (h = a.first).is_a? Hash and (type = h[:type] || h['type']) and (klass = type.constantize) != self
        raise "wtF hax!!"  unless klass < self  # klass should be a descendant of us
        return klass.new(*a, &b)
      end

      new_without_cast(*a, &b)
    end
    alias_method_chain :new, :cast
  end
end

Что отлично сработало для меня с минимальным кодом - я не знаю, хак это или нет, но работает, и довольно чисто. Мне понравилось то, что это всего лишь 10 строк кода.

0 голосов
/ 01 февраля 2010

Я не знаю, сколько у вас типов, но я просто использовал отдельные контроллеры и представления для разных типов в прошлом. Таким образом, вы не создаете новый объект базового класса и не пытаетесь установить тип, вы просто используете модель, которая наследуется от базового класса. Каждая новая страница редактирования ваших ресурсов может отображать общий фрагмент в блоке form_for. Частичное будет содержать ваше file_field.

Таким образом, когда форма отправлена, она отправляется на правильный контроллер, вызывает правильный resource.new, и все в порядке.

Недостаток, конечно, заключается в большем количестве файлов, и на любой странице, на которую вы ссылаетесь «добавить новый файл», необходимо добавить несколько ссылок, таких как «добавить новый файл этого типа», «добавить новый файл такого типа» и т. Д.

Что касается установки типа в форме, я не уверен, что это работает, я сомневаюсь в этом, но просто попробуйте (дайте нам знать). Вы можете сделать этот тип выпадающим из списка select_tag, а при изменении используйте Javascript, чтобы изменить местоположение действия в форме.

Отредактированы и добавлены основные работы вокруг

Не то, чтобы мне нравилось это решение, и я сомневаюсь, что оно ни в коем случае не лучшее, но если вам действительно не нужны отдельные контроллеры, и вам нужно, чтобы оно работало, вы можете сделать что-то вроде этого:

class XmlFile < ActiveRecord::Base
end

class XmlFileTypeA < XmlFile 
end

class XmlFileTypeB < XmlFile 
end

def create
    # Leaving this case statement in the controller for simplicity but you probably want to move this to the model
    case params[:chosen_xml_type]
      when "file_type_a"
        @item = XmlFileTypeA.new(params)
      when "file_type_b"
        @item = XmlFileTypeB.new(params)
      else
        raise "Unknown file type!"
      etc
    end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...