Ok here are my notes on setting up a many to many association including 
adding child records to the parent, both directions.  Please comment and let 
me know what you think.  Once the dust settles I'll post it as a recipe on 
hobocentral.

Bob

Many to Many in Hobo

Start out with a new hobo app

hobo g resource book title:string

hobo g resource author name:string

hobo g model book_author

Add has_many assotications to book.rb, author.rb and book_author.rb

Add to book.rb

  has_many :book_authors, :dependent => :destroy

  has_many :authors, :through => :book_authors, :accessible => :true

  children :authors

Add to author.rb

  has_many :book_authors, :dependent => :destroy

  has_many :books, :through => :book_authors, :accessible => :true

  children :books

Add to book_author.rb

  belongs_to :book

  belongs_to :author

create and run the migration

hobo g migration

Run the app

At this point you can add authors to books and books to authors but the book 
or author must already exist.  There is no direct way to add a new author to 
a book or new book to an author you need to first create the book/author and 
then make the association separately.  Wouldn't it be nice to be able to add 
a new author to a book while editing the book?  You can do this very easily 
with Hobo and auto_actions_for int he control in a one to many association 
but that doesn't work totally automaticly for many to many associations.

First we are going to use Hobo's auto_actions_for in the controllers to 
create the routes for us.

Add to authors_controller.rb

  auto_actions_for :books, [:create, :new]

Add to books_controller.rb

  auto_actions_for :authors, [:create, :new]

If you go to a book or author you won't see any changes to the UI. If this 
were a one to many association we would have a New link below the collection 
of books or authors but there isn't one so lets add it.

First lets confirm we have the appropriate routs created for us

run a rake routes from the command prompt and you should see these in the 
list of all the routes

create_author_for_book POST   /books/:book_id/authors(.:format)       
{:controller=>"authors", :action=>"create_for_book"}

   new_author_for_book GET    /books/:book_id/authors/new(.:format)   
{:controller=>"authors", :action=>"new_for_book"}

create_book_for_author POST   /authors/:author_id/books(.:format)     
{:controller=>"books", :action=>"create_for_author"}

   new_book_for_author GET    /authors/:author_id/books/new(.:format) 
{:controller=>"books", :action=>"new_for_author"}

Ok we have the routes now to add them.

Create a books and authors subdir under views.

Create show.dryml in the books dir
<show-page>

  <after-collection-section:>

      <a:authors action="new" if="&can_create?(BookAuthor)">

        <ht key="author.actions.new" count="1">

          New Author

        </ht>

      </a:authors>

  </after-collection-section:>

</show-page>

And a show.dryml is authors dir

<show-page>

  <after-collection-section:>

      <a:books action="new" if="&can_create?(BookAuthor)">

        <ht key="book.actions.new" count="1">

          New Book

        </ht>

      </a:books>

  </after-collection-section:>

</show-page>

Now if you view a book or an author there is a link to add a new book or 
author but they don't quite work yet so on we march.

We need to modify the forms that are auto generated for entering books and 
authors.  Open up your views/taglibs/applicatoin.dryml and add the 
following.


<extend tag="form" for="Author">

  <old-form replace>

    <field-list: fields="name, books" />

    <after-field-list:> <%= hidden_field(:book, :id) %></after-field-list:>

    <actions:>

      <submit label="#{ht 'author.actions.save', :default=>['Save']}" 
param/>

      <or-cancel with="&@book" param="cancel"/>

    </actions:>

  </old-form>

</extend>


<extend tag="form" for="Book">

  <old-form replace>

    <field-list: fields="title, authors" />

    <after-field-list:> <%= hidden_field(:author, :id) 
%></after-field-list:>

    <actions:>

      <submit label="#{ht 'book.actions.save', :default=>['Save']}" param/>

      <or-cancel with="&@author" param="cancel"/>

    </actions:>

  </old-form>

</extend>


now add this to your books_controller.rb

  def new_for_author

    @author = Author.find_by_id(params[:author_id])

    hobo_new

  end


  def create

    @author = Author.find_by_id(params[:author][:id])

    hobo_create do

      @this.authors=[@author]

      redirect_to @author if valid?

    end

  end


and this to your authors_controller.rb

  def new_for_book

    @book = Book.find_by_id(params[:book_id])

    hobo_new

  end


  def create

    @book = Book.find_by_id(params[:book][:id])

    hobo_create do

      @this.books=[@book]

      redirect_to @book if valid?

    end

  end


You can now add new books to authors and new authors to books.


Bob

-- 
You received this message because you are subscribed to the Google Groups "Hobo 
Users" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/hobousers/-/d5-JPBLqSeMJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/hobousers?hl=en.

Reply via email to