Rails: Many to many polymorphic relationships

前端 未结 7 2191
孤城傲影
孤城傲影 2021-01-30 00:17

See comments for updates.

I\'ve been struggling to get a clear and straight-forward answer on this one, I\'m hoping this time I\'ll get it! :D I definitely have

7条回答
  •  梦谈多话
    2021-01-30 00:56

    The has_many_polymorphs solution you mention isn't that bad.

    class Task < ActiveRecord::Base
      has_many_polymorphs :targets, :from => [:store, :software, :office, :vehicle]
    end
    

    Seems to do everything you want.

    It provides the following methods:

    to Task:

    t = Task.first
    t.targets   # Mixed collection of all targets associated with task t
    t.stores    # Collection of stores associated with task t
    t.softwares # same but for software
    t.offices   # same but for office
    t.vehicles  # same but for vehicles
    

    to Software, Store, Office, Vehicle:

    s = Software.first    # works for any of the subtargets.
    s.tasks               # lists tasks associated with s
    

    If I'm following the comments correctly, the only remaining problem is that you don't want to have to modify app/models/task.rb every time you create a new type of Subtarget. The Rails way seems to require you to modify two files to create a bidirectional association. has_many_polymorphs only requires you to change the Tasks file. Seems like a win to me. Or at least it would if you didn't have to edit the new Model file anyway.

    There are a few ways around this, but they seem like way too much work to avoid changing one file every once in a while. But if you're that dead set against modifying Task yourself to add to the polymorphic relationship, here's my suggestion:

    Keep a list of subtargets, I'm going to suggest in lib/subtargets formatted one entry per line that is essentially the table_name.underscore. (Capital letters have an underscore prefixed and then everything is made lowercase)

    store
    software
    office
    vehicle
    

    Create config/initializers/subtargets.rb and fill it with this:

    SubtargetList = File.open("#{RAILS_ROOT}/lib/subtargets").read.split.reject(&:match(/#/)).map(&:to_sym)
    

    Next you're going to want to either create a custom generator or a new rake task. To generate your new subtarget and add the model name to the subtarget list file, defined above. You'll probably end up doing something bare bones that makes the change and passes the arguments to the standard generator.

    Sorry, I don't really feel like walking you through that right now, but here are some resources

    Finally replace the list in the has_many_polymorphs declaration with SubtargetList

    class Task < ActiveRecord::Base
      has_many_polymorphs :targets, :from => SubtargetList
    end
    

    From this point on you could add a new subtarget with

    $ script/generate subtarget_model home
    

    And this will automatically update your polymorphic list once you reload your console or restart the production server.

    As I said it's a lot of work to automatically update the subtargets list. However, if you do go this route you can tweak the custom generator ensure all the required parts of the subtarget model are there when you generate it.

提交回复
热议问题