Rails STI using ONE form

I have a form that allows me to add files of different formats to the stream. Thus, a stream consists of many files, these files are XML files, but basically they have different schemes. I have one form that allows the user to add any file that they need, I use STI (which works fine when the data is already in the table), my problem is adding data to the table.

The form has 1 input field, just the file_field field, which allows the user to select the file that they want to upload. Since I have only one form, I cannot create an instance of the correct object, I have to do it programmatically .. and I'm not sure how to do it.

I just (or can I) add a drop-down list with possible types and call this "type" field so that when sending the form the rails create an instance of the record type, because the type attribute is provided?

What is the best practice for this. I run the rails 2.3.4.

+6
polymorphism ruby-on-rails single-table-inheritance
source share
2 answers

I found a solution at 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 

Which worked fine for me with minimal code - I don't know if it was hacker or not, but it works, and is pretty clean. I liked the fact that its only 10 lines of code.

+3
source share

I don't know how many types you have, but I just used separate controllers and views for different types in the past. Thus, you are not creating a new object of the base class and you are not trying to set the type, you are simply using a model that inherits from the base class. Each new / edit page for your resources can display a shared partial in the form_for block. Partial will contain your file field.

Thus, when the form is submitted, it will return to the correct controller, calling the correct resource. New, and everything is in order.

Of course, the drawback is more files and any page that you link to "add a new file", you need to add several links, such as "add a new type of this file", "add a new file type", etc.

As for setting the type in the form, I'm not sure if this works, I doubt it, but just try (let us know). You can make this type drop down select_tag, and when changing, use Javascript to change the location of the action on the form.

Edited and added the main work around

Not that I liked this solution, and I doubt that it is by no means the best, but if you really do not need separate controllers and you need to make it work, you can do something like this:

 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 
0
source share

All Articles