Search code examples
ruby-on-railsmodel-associationssingle-table-inheritancesti

Rails Nested create STI


I have 4 clases, with an STI on Instance.

Workspace, Project, Task, Instance, (type1 < Instance) and (type2 < Instance).

With proper associations. (Workspace has_many projects, has_many task through projects, so on)

And I have this nested create (worked before implementing STI):

if (%w(type1 type2).include?(params[:type]))

 sti_class = params[:type].classify.constantize

 workspaces.find_by_name(name: w_name). 
 projects.where( name: p_name).first_or_create!.
 tasks.where(name: t_name).first_or_create!.
 sti_class.create() 

now, that doesn't work, I can't figure out a way.

However, the following works, but I want to keep the nested create.

task=  workspaces.find_by_name(name: w_name). 
        projects.where( name: p_name).first_or_create!.
        tasks.where(name: t_name).first_or_create!

sti_class.create(task_id: task.id) 

How can I keep the nested create?


Solution

  • The problem I could immediately deduce is that the sti_class method isn't defined in your Task model, as you're adding it to the method chain.

    Don't really think you're following the best practice here, but to immediately resolve the issue, you should probably do something like:

    if (%w(type1 type2).include?(params[:type]))
     # depending on the association between the type(s) and the tasks, 
     # you'd need to either singularize or pluralize here, I'd assume 
     # task has many types, therefore pluralize
    
     sti_class = params[:type].pluralize
    
     # if you're already calling `find_by_name`, you don't need to pass 
     # the name option here anymore, but the name argument
    
     workspaces.find_by_name(w_name). 
     projects.where(name: p_name).first_or_create!.
     tasks.where(name: t_name).first_or_create!.
     send(sti_class).create