4

I'm a bit confused about STI in rails.

My situation: I have a Contact model that has description and data string fields, to store some contact like phone, fax, email, etc.

Now when I have some specific contact type like phone number of email address I want to walidate the data format in different way and I want to make some different formating on output.

I decided to use STI as all the models have the same data with just different behaviour. And I have some questions regarding forms and CRUD operations as I don't want to go against Rails conventions.

  1. How do I make a dropdown list in form with model type? Should I hardcode it or is there some more automated way?

  2. How do I create a record? Should I use switch statement and according to received type create new model of according instance?

  3. How should I update it if I'm going to change the model type? Cast the object to new class? Or create a new object and destroy the previous one?

I'll be very thankfull for your help!

Uko
  • 13,134
  • 6
  • 58
  • 106

2 Answers2

2
  1. Yes, should do a hardcore as there no default store for your STI models.
  2. Generally, yes. But With Rails you could just use camelize.constantize to get class from string. Another way is just use parent model, and set type field manually. As with STI all records are in the same table and then all are of the parent class.
  3. If you wish to update, just update type field. Then you could re-query to force Rails to get new object of different type.
Mark Huk
  • 2,379
  • 21
  • 28
  • Thank you for your reply. But will the validation work for a specific model if I'll just set a type field? – Uko Jul 20 '12 at 12:01
  • 2
    @Uko yes, if you do `@model = type.camelize.contantize.new(params[:model])` – Jesse Wolgamott Jul 20 '12 at 14:33
  • Wow, that's really nice. One more thing. How should I handle the update? Should I do something like `@model.becomes(type.camelize.contantize)` and then `@model.update_attributes(params[:model])` ? – Uko Jul 20 '12 at 16:54
0

You could create a model like this :

Type < ActiveRecord::Base
  has_many :contacts
end

You could use this command rails g model Type name:string, add a type_id column in your contact and migrate the database.

end change your contact's model like this :

Contact < ActiveRecord::Base
  belongs_to :type
end

Now, in your form, you could use this :

select("type", "type_id", Type.all.collect {|t| [ t.name, t.id ] }, { :include_blank => true })

It should resolve your problem.

Now you can do something like this :

@emails = Type.find_by_name('email').contacts

Or use scopes.

Dougui
  • 7,142
  • 7
  • 52
  • 87
  • Thank you for this sujjestion, I've thought about this option, but I think that STI is a better design strategy, as I have exactly the same data and just need different validations and formating, etc. So if I use STI validation vill be done depending on the model tope by itself, and in your solution I'll need to use some pre-validation callbacks with `switch` statements – Uko Jul 20 '12 at 12:07