Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails has_and_belongs_to_many & has_many :through scaffolding

Tags:

Is there a way to generate a scaffold for Rails models that have either a has_and_belongs_to_many or has_many :through relationship? If not, is there a developmental reason why some basic form of this functionality has not been included? Rails requires developers to generate and edit a "custom" "join table migration." Is the necessary attention to detail a way of reminding Rails developers of some important fact or is this simply an example of how Rails is a 'work in progress?'

A quick Stackoverflow search for:

"has_and_belongs_to_many" yields 821 questions   "has_many :through" yields 933 questions   

... and many of these start with "How do I..." So it seems the topic is not trivial and relevant to SO users. I Guess I am wondering why it has not received attention. Is the matter more complex than it seems? The feature set for Rails seems so extensive. I keep wondering why scaffolding for associations with join tables has been omitted.

Please focus your answer toward the assertions above or "include statement like, "A scaffolding would have to include..." or "A rails generate script would need..."

Thanks!

like image 320
Perry Horwich Avatar asked Oct 10 '11 05:10

Perry Horwich


People also ask

What is Has_and_belongs_to_many?

Rails offers two different ways to declare a many-to-many relationship between models. The first way is to use has_and_belongs_to_many, which allows you to make the association directly: The second way to declare a many-to-many relationship is to use has_many :through.

What is difference between has many through and Has_and_belongs_to_many?

Aside from the actual code you write, the main difference between the two approaches is that in a has_many :through relationship, the JOIN table has its own model, while a has_and_belongs_to_many relationship has no JOIN model, just a database table.

What is a polymorphic association in rails?

In Ruby on Rails, a polymorphic association is an Active Record association that can connect a model to multiple other models. For example, we can use a single association to connect the Review model with the Event and Restaurant models, allowing us to connect a review with either an event or a restaurant.


1 Answers

I like your question, I have wondered for myself why this is not included in Rails (and as I suspect not available as a Gem). Here are some of the reasons why that could be a problem. I will them explain at the typical example with assemblies and parts.

  1. Scaffolding works by using generators to create files. If you migrate to a newer version, there is sometimes the option to update existing files by doing the following steps:

    • Copy existing ones to a new name.
    • Overwrite existing ones by new ones.

    That implies that there is no notion of adding to files or changing files. EDIT: This is not true, there are mechanisms to add to files and even change in files.

  2. If you look at the generation of e.g. has_many :through (should be similar to has_and_belongs_to_many) you have to do the following things:

    • Add a migration that creates the join table.

      ==> Should be possible for scaffolding by doing: rails g scaffold_hmt Assembly Part

    • Add a model for that join model.

      ==> Should be possible for scaffolding by the previous scaffold.

    • Change existing models to include the lines:

      assembly.rb: has_many 'assemblies_parts'; has_many :parts, :through => 'assemblies_parts'

      part.rb: has_many 'assemblies_parts'; has_many :assemblies, :through => 'assemblies_parts'

      ==> So no scaffolding possible

    • What to do with views is wide open. There are examples at RailsCast how to do it, but it is not at all trivial, and there is no one single technique that works well in all circumstances. I do think that the different patterns could be implemented as templates for scaffolding (e.g. to use checkboxes or multi-select lists or text entry with completion). The problem is the same as in has_many views, however.

So as a summary, a scaffold could be worth a try (see the following paragraph). The RailsGuides to Creating and Customizing Rails Generators & Templates seems plausible at least. And a solution that generates parts of files, names them accordingly and helps in the output of the scaffold on the console to do the rest by hand could be worth a try.


I have tried yesterday to come up with a partial solution, you may have a look at it at GitHub. It works like that:

  1. Copy the contents of the directory scaffold_hmt (stands for has_many :through) to your rails application directory lib/generators.
  2. You may call then the generator with: rails g scaffold_hmt Assembly Part.
  3. It will then generate:
    • Migration for the join table
    • Model for the join table
  4. It fails to change the files:

    • Model assembly.rb
    • Model part.rb

    The reason for that is that the finding of the right place is not trivial. As a workaround, it prints out what should have inserted into the files.

    c:\apps\ruby\rails3\minds>rails generate scaffold_hmt Assembly Part       create  db/migrate/20111011135944_create_assemblies_parts.rb       create  app/models/assemblies_part.rb Try to insert into file: app/models/assembly.rb the following statements:  has_many :assemblies_parts has_many :parts, :through => :assemblies_parts       insert  app/models/assembly.rb Try to insert into file: app/models/part.rb the following statements:  has_many :assemblies_parts has_many :assemblies, :through => :assemblies_parts       insert  app/models/part.rb 

Give it a try and see if that will help you.

like image 176
mliebelt Avatar answered Oct 10 '22 19:10

mliebelt