2009-10-21 2 views
2

Я использую однонаправленное наследование для моего приложения. Мой полиморфный тип - это обслуживание только с одним подтипом, названным OilChange. У меня возникают проблемы с созданием моих записей в моем методе создания в контроллере. Вот код.Создание записей наследования отдельных таблиц в рельсах

@log = Log.new(params[:log]) 
@log.maintenance = Maintenance.new(params[:maintenance]) 

Параметр [: maintenance] hash имеет ключи {: name,: type}. Я могу подтвердить их существование и ценности, печатая их следующим образом

print params[:maintenance][:name] 
print params[:maintenance][:type] 

Если я перехожу в «Oilchange» для значения: тип ключа, запись обслуживание имеет тип технического обслуживания и не Oilchange. Я могу проверить, найдя запись в консоли REPL. Поле типа nil. Я могу заставить его работать, как я хочу, добавив следующую строку.

@log.maintenance.type = params[:maintenance][:type] 

Но это уродливо. Мне интересно, почему метод create не задает поле типа, так как поле имени просто находит?

Два типа вы видите выглядеть в моем schema.rb

create_table "logs", :force => true do |t| 
    t.date  "date" 
    t.text  "description" 
    t.string "title" 
    t.string "summary" 
    t.integer "car_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.integer "maintenance_id" 
    t.integer "mileage" 
end 

create_table "maintenances", :force => true do |t| 
    t.string "name" 
    t.string "type" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.string "oil_brand" 
    t.string "oil_type" 
    t.string "oil_filter_type" 

Мои модели выглядеть следующим образом.

class Log < ActiveRecord::Base 
belongs_to :car 
has_and_belongs_to_many :tags 
    belongs_to :maintenance 
end 

class Maintenance < ActiveRecord::Base 
    has_one :log 
end 

class OilChange < Maintenance 
end 

TIA!

ответ

3

Конкретный ответ заключается в том, что атрибут type, как и многие специальные атрибуты Rails, защищен от массового присвоения. (Смотри :attr_protected в документации.)

Ответ на более общую проблему заключается в том, что вы недостаточно доверяете своим моделям. Если вы хотите создать запись типа OilChange, вы не должны звонить Maintenance.new или Maintenance.create. Вызовите OilChange.new или OilChange.create, а Rails автоматически позаботится о настройке типа и выполнении всех фоновых работ для вас.

+0

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

+2

Не имеет значения. Динамика Руби. > 8-> Предположим, у вас есть раскрывающийся список «Тип обслуживания». Просто верните значения из раскрывающегося списка, как «OilChange», и вы можете вызвать 'params [: maintenance_type] .constantize.new', чтобы получить свой объект. (_constantize_ - это метод, предоставляемый ActiveSupport.) – SFEley

+0

Или вы можете установить «тип» явно: maintenance.type = «OilChange» –

0

Попробуйте следующий код:

begin 
    klass = Module.const_get(params[:maintenance][:type]) 
    @log.maintenance = klass.new(params[:maintenance]) 
    if ! @log.maintenance.is_a?(Maintenance) 
    @log.maintenance = Maintenance.new(params[:maintenance]) 
    end 
rescue NameError 
    @log.maintenance = Maintenance.new(params[:maintenance]) 
end 

Если вы хотите иметь только подклассы технического обслуживания в вашей базе данных, выполните следующие действия в классе Maintenance:

class Maintenance < ActiveRecord::Base 
    validates_presence_of :type 
    # other stuff goes here 
end 

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

Если ваши модели используют пространство имен вы можете посмотреть в this article вместо использования Module.const_get:

Смежные вопросы