Rails Nested Form

Hi everyone,

I have followed the tutorial given by Ryan at
http://railscasts.com/episodes/196-nested-model-form-part-1 and it works
great. However it doesn't do what I need and not sure if its a concept
issues or I might need to change my models.

The models I have his

- Customer
- Book, and
- BookManager

Here are the relationship
Customer
    has_many :book_managers
  accepts_nested_attributes_for :book_managers, allow_destroy: :true
BookManager
  attr_accessible :customer_id, :visible, :books_attributes
  belongs_to :customer
  has_many :books
  accepts_nested_attributes_for :books, allow_destroy: :true
Book
  belongs_to :book_manager
  attr_accessible :book_manager_id, :description

Here a diagram

-------------|1---------*|-------------|*---------1|-------------|
Customer | | BookManager | | Book |
-------------| |-------------| |-------------|
ID | | ID | | ID |
First | | customer_id | | Description |
Last | | book_id | |-------------|
Email | | isVisible |
Password | | isDeleted |
-------------| |-------------|

So what I am trying to do is when a customer goes into customer#edit
then a form show up. But unlike the tutorial it doesn't create a new
customer but a new bookmanager and keep the integrity and also create a
new book. That his my problem, not sure how to do it and thank you. Here
my customerController and when clicking the button it does say no
BookManager controller but not sure how to approach it at the moment.

CustomerController
  @book_manager = BookManager.new
  @book_manager.books.build
#Need to associate it with customer
#Need to generate some control of bookManager because of BookManager.new

Hi everyone,

I have followed the tutorial given by Ryan at
http://railscasts.com/episodes/196-nested-model-form-part-1 and it works
great. However it doesn't do what I need and not sure if its a concept
issues or I might need to change my models.

The models I have his

- Customer
- Book, and
- BookManager

Here are the relationship
Customer
    has_many :book_managers
  accepts_nested_attributes_for :book_managers, allow_destroy: :true
BookManager
  attr_accessible :customer_id, :visible, :books_attributes
  belongs_to :customer
  has_many :books
  accepts_nested_attributes_for :books, allow_destroy: :true
Book
  belongs_to :book_manager
  attr_accessible :book_manager_id, :description

Here a diagram

>-------------|1---------*|-------------|*---------1|-------------|
> Customer | | BookManager | | Book |
>-------------| |-------------| |-------------|
> ID | | ID | | ID |
> First | | customer_id | | Description |
> Last | | book_id | |-------------|
> Email | | isVisible |
> Password | | isDeleted |
>-------------| |-------------|

You said above BookManager has many books and Book belongs_to book
manager. In that case book manager should not have book_id, it is
book that should have a book_manager_id. Though I suspect it is the
model definitions that are wrong.

Colin

Colin Law wrote in post #1071797:

- Book, and
  accepts_nested_attributes_for :books, allow_destroy: :true
> First | | customer_id | | Description |
> Last | | book_id | |-------------|
> Email | | isVisible |
> Password | | isDeleted |
>-------------| |-------------|

You said above BookManager has many books and Book belongs_to book
manager. In that case book manager should not have book_id, it is
book that should have a book_manager_id. Though I suspect it is the
model definitions that are wrong.

Colin

My bad yeah I must of not seen it when writing it

-------------|1---------*|-------------|*---------1|-----------------|
Customer | | BookManager | | Book |
-------------| |-------------| |-----------------|
ID | | ID | | ID |
First | | customer_id | | book_manager_id |
Last | | isDeleted | | Description |
Email | | isVisible | |-----------------|
Password | |-------------|
-------------|

The issue remains the same, how can i create a new instance from an
other bookmanager, is it doable in ruby?

Colin Law wrote in post #1071797:

- Book, and
accepts_nested_attributes_for :books, allow_destroy: :true
> First | | customer_id | | Description |
> Last | | book_id | |-------------|
> Email | | isVisible |
> Password | | isDeleted |
>-------------| |-------------|

You said above BookManager has many books and Book belongs_to book
manager. In that case book manager should not have book_id, it is
book that should have a book_manager_id. Though I suspect it is the
model definitions that are wrong.

Colin

My bad yeah I must of not seen it when writing it
>-------------|1---------*|-------------|*---------1|-----------------|
> Customer | | BookManager | | Book |
>-------------| |-------------| |-----------------|
> ID | | ID | | ID |
> First | | customer_id | | book_manager_id |
> Last | | isDeleted | | Description |
> Email | | isVisible | |-----------------|
> Password | |-------------|
>-------------|

The issue remains the same, how can i create a new instance from an
other bookmanager, is it doable in ruby?

It sounds to me as though you really want a has_many :through rather than what you have.

Customer
has_many :book_managers
has_many :books, :through => :book_manager

Then a customer can have multiple books, and each relationship to a book is through a corresponding book_manager. Or do you need each customer to have N book_managers, and each of those book_managers has N books? I'm not clear why book_manager is standing between the customer and her books. If it's the latter, then your nested form would have to be two layers deep, and I would be tempted to have a form_for :book_manager masquerade as the form for the customer to acquire books.

Walter

Walter Davis wrote in post #1071811:

Customer
has_many :book_managers
has_many :books, :through => :book_manager

Then a customer can have multiple books, and each relationship to a book
is through a corresponding book_manager. Or do you need each customer to
have N book_managers, and each of those book_managers has N books? I'm
not clear why book_manager is standing between the customer and her
books. If it's the latter, then your nested form would have to be two
layers deep, and I would be tempted to have a form_for :book_manager
masquerade as the form for the customer to acquire books.

Walter

Yeah I might want more a has_many through, here a sample of the database
it should be like

Customer
ID First Last Email
1 John Smith example@example.com
2 Heather Clark example@example.com
3 Mike Watson example@example.com

BookManager
Id CustomerID isVisible isDeleted
1 1 0 1
2 3 1 0
3 2 1 0
4 1 1 0

Book
Id BookManagerID Description
1 1 Harry Potter
2 2 The Javascript Bible
3 3 Harry Potter
4 4 PHP

At the end however i want a form that the customer can create a new
bookManager which his associated with a book and manipulate the data
from BookManager and Books in the customer#edit.

You have to get the relationships right before worrying about forms.
You still have not made it clear what the relationship between books
and book_managers is. Is one book_manger associated with a number of
books or is one book associated with a number of book_managers, or is
it a one to one relationship?

Colin

It sounds like you really need to restructure this as has_many :through, since all your BookManager is adding to the Book is the visible and deleted flags. (And I would name them exactly that, since you can then use the visible? and deleted? meta methods that are automatically added to boolean columns.) Your customer#edit form would have a fields_for :books section, and the usual nested fields for books, so your users would not need to know anything about the BookManager model, only the Book, and you could add the checkboxes for the visible and deleted from your :through relationship. I realize, as I'm writing this, that I don't have a canonical example of how you would add a checkbox to toggle the attribute on the :through object, so I'm going to post a separate question about that...

Walter

Colin Law wrote in post #1071823:

That is only half of the associations. How many customers are
associated with each manager and how many book managers are associated
with each book?

Show us the model relationships that the above implies for each model.

Colin

Colin Law wrote in post #1071831:

it a one to one relationship?

Colin

A customer has many BookManager
A bookManager has one book

That is only half of the associations. How many customers are
associated with each manager and how many book managers are associated
with each book?

Show us the model relationships that the above implies for each model.

Colin

Here what I build up with has many

class Book < ActiveRecord::Base
        # RELATIONSHIP
  belongs_to :book_manager
  def customer
    book_manager.customer
  end
  attr_accessible :book_manager_id, :description
class BookManager < ActiveRecord::Base
        # RELATIONSHIP
  belongs_to :customer
  has_one: :book
  accepts_nested_attributes_for :books, allow_destroy: :true
  attr_accessible :customer_id, :visible, :books_attributes
class Customer < ActiveRecord::Base
        # RELATIONSHIP
  has_many :book_managers
  has_many :books, :through => :book_managers
  accepts_nested_attributes_for :book_managers, allow_destroy: :true
  attr_accessible :admin, :first_name, :last_name, :middle_name, :email,
:email_confirmation, :password, :password_confirmation, :image,
:book_managers_attributes, :locale

I think his a correct relationship model.

If you have a one-to-one relationship between books and book managers
why not just combine the two tables and make life easier?

Colin

Colin Law wrote in post #1071834:

If there is only a slight possibility then do it the easy way for the
moment. You can always refactor it later if you need to. Make sure
you have complete automated test coverage of course so that you can be
sure it all still works after refactoring. I don't understand how
having two tables with a one-to-one relationship can be easier than
one table. If that were the case then you could split every field out
into separate tables and life would be even easier.

But even if you keep them separate, if the slight possibility did
eventually occur would it be each book has many managers or each
manager has many books?

Colin

Colin Law wrote in post #1071842:

I am just wondering how I am suppose to build a bookManager has follow.
The models his has follow

-------------|1---------*|-------------|
Customer | | BookManager |
-------------| |-------------|
ID | | ID |
First | | customer_id |
Last | | isDeleted |
Email | | isVisible |
Password | | description |
-------------| |-------------|

The association is as follow

class Customer < ActiveRecord::Base
# RELATIONSHIP
    has_many :book_managers
    accepts_nested_attributes_for :book_managers, allow_destroy: :true
    attr_accessible :admin, :first_name, :last_name, :middle_name,
:email, :email_confirmation, :password, :password_confirmation, :image,
:book_managers_attributes, :locale
end

class BookManager < ActiveRecord::Base
    belongs_to :customer
    attr_accessible :customer_id, :visible, :description
end
The form is like this Customer#edit view

  <h3>Book</h3>
  <div><%= render 'book_managers/form' %></div>
BookManagers/Forms

<%= form_for(@book_manager) do |f| %>
  <fieldset>
    <%= f.label :description %>
    <%= f.text_field :description %>
  </fieldset>

  <fieldset>
    <%= f.check_box :visible %>
    <%= f.label :visible %>
  </fieldset>

  <div class="actions">
    <%= f.submit %>
  </div>
and this is the big prize puzzle. The controllers At the moment i have
nothing in the BookManager controller because its the caller that tend
to have the data information. But i am really confused on the customer
Controller.

What i want is to associate and fill up the BookManager with customer
and its attribute. here what i have for now.

CustomerController

        @customer = Customer.find(params[:id])

# @book_manager = BookManager.new
# bm = @customer.book_managers.build
# bm.books.build

        @book_manager = @customer.book_managers.build

What has that got to do with merging book and book manager which is a
one to one relationship?

Colin

Colin Law wrote in post #1071869: